2012년 12월 15일 토요일

Custom View 만들기

Custom View 만들기

1. 생성자

View 객체는 코드 상에서 만들어 질 수도 있고 xml 파일을 통해서 만들어 질 수도 있다.
그러므로 아래 세 종류의 생성자를 반드시 작성하자.
public CustomView(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
}

public CustomView(Context context, AttributeSet attrs) {
 super(context, attrs);
}

public CustomView(Context context) {
 super(context);
}

AttributeSet 인자에 xml 파일에서 기술한 속성 값들이 담겨서 전달된다.

2. 함수 Override

기본적으로 onMeasure() 함수와 onDraw() 함수를 상속받아 작성한다.

  • onMeasure() 함수는 View 의 크기를 결정할 때 불리는 함수
  • onDraw() 함수는 View 가 화면에 그려질 때 불리는 함수
    • invalidate() 함수를 부르면 강제로 화면을 갱신하면서 onDraw() 함수가 불리게 된다.

1) onMeasure() 함수 작성

크기 모드

onMeasure() 함수로 넘어온 인자 값을 MeasureSpec.getMode() 함수를 이용해서 크기 mode 값을 얻는다.
크기 모드 값은 UNSPECIFIED, AT_MOST 또는 EXACTLY 값 중에 하나이다.
wrap_content 로 설정한 경우 AT_MOST 모드로 전달되고, match_parent (또는 fill_parent) 로 설정한 경우 EXACTLY 모드로 전달된다.
UNSPECIFIED 모드는 값이 정의되지 않은 경우인데 이런 경우는 의미가 없다고 본다. (코드로 View 를 작성하는 경우 발생할 수 있다고 한다)

  • UNSPECIFIED 모드의 경우 그냥 인자로 넘어온 그대로 넘겨준다.
  • AT_MOST 모드의 경우 내용물의 크기를 계산한 값을 넘겨준다.
  • EXACTLY 모드의 경우 MeasureSpec.getSize() 함수로 얻은 값을 설정한다.
반드시 마지막에는 setMeasuredDimension() 함수로 계산된 width 와 height 값을 넘겨주어 설정해야 한다.

예)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  
 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  
 int width = (int)getDip(10);
 int height = (int)getDip(10);
  
 switch (widthMode) {
 case MeasureSpec.UNSPECIFIED: // unspecified
  width = widthMeasureSpec;
  break;
 case MeasureSpec.AT_MOST:  // wrap_content
  break;
 case MeasureSpec.EXACTLY:  // match_parent
  width = MeasureSpec.getSize(widthMeasureSpec);
  break;
 }
  
 switch (heightMode) {
 case MeasureSpec.UNSPECIFIED: // unspecified
  height = heightMeasureSpec;
  break;
 case MeasureSpec.AT_MOST:  // wrap_content
  break;
 case MeasureSpec.EXACTLY:  // match_parent
  height = MeasureSpec.getSize(heightMeasureSpec);
  break;
 }
  
 setMeasuredDimension(width, height);
}

// 사용편리를 위해 작성한 함수 : dip 값을 pixel 값으로 변환하는 함수
public float getDip(float value) {
 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
}

2) onDraw() 함수 작성
예)
@Override
protected void onDraw(Canvas canvas) {
 Paint p = new Paint();
 p.setColor(Color.RED);
 canvas.drawRect(1, 1, canvas.getWidth() - 1, canvas.getHeight() - 1, p);
}

Canvas 클래스에는 그림을 그리기 위한 많은 함수들이 제공된다.
선, 사각형, 원, path, 글자, 비트맵 등을 그리는 함수가 제공된다.
그리고 그림을 그리는 함수에는 Paint 인자를 넘겨주는데 그림을 그리기 위한 속성들을 설정해서 넘겨 주게 된다.
면색, 선색, 그리기 스타일 (fill, stroke, fill & stroke) 등 이다.

!) dip, sp 등의 단위를 pixel 값으로 변환하기
TypedValue.applyDimension() 함수를 이용해서 여러 단위로 설정된 값을 pixel 값으로 변환 할 수 있다.

예)
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());

TypedValue 클래스에는 여러 단위들이 정의 되어 있다.

3) ViewGroup 을 상속 받은 경우 dispatchDraw() 함수를 구현한다.

4) scroll 이벤트를 처리하고 싶다면 onScrollChanged() 함수를 구현한다.

댓글 없음:

댓글 쓰기