간단한 Custom View 작성
간단하게 Custom View 를 작성해 보자. 사실 View 는 기능을 주려면 작성할 것이 많아진다. 하지만 그런것들은 덧붙여지는 것에 지나지 않는다. Custom View 의 핵심은 내가 원하는 View 를 만드는 것이다. 즉 내가 원하는 그림을 그리는 것이다.
이런 관점에서 간단하게 'ㅗ' 를 그려주는 View 를 만들어보기로 하자. 소스는 ref. 1 의 소스를 참고해서 만들었다.
만드는 것은 아래에 적혀있는 것만 작성하면 된다.
- attr.xml
- .java
- constructor(생성자)
- onDraw()
- onMeasure()
source codes
values/attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DividerView">
<attr name="dvColor" format="color" />
<attr name="dvHeight" format="dimension" />
<attr name="dvThickness" format="dimension" />
</declare-styleable>
</resources>
DividerView.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import com.hbwhale.seedmoney.R;
/**
* Created by namh on 2016-03-26.
*/
public class DividerView extends View {
private Paint _paint;
private int _lineHeight;
public DividerView(Context context, AttributeSet attrs) {
super(context, attrs);
int dashGap, lineHeight;
int color;
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DividerView, 0, 0);
try {
lineThickness = a.getDimensionPixelSize(R.styleable.DividerView_dvThickness, 1);
_lineHeight = a.getDimensionPixelSize(R.styleable.DividerView_dvHeight, getSuggestedMinimumHeight());
color = a.getColor(R.styleable.DividerView_dvColor, 0xff000000);
} finally {
a.recycle();
}
_paint = new Paint();
_paint.setAntiAlias(true);
_paint.setColor(color);
_paint.setStyle(Paint.Style.STROKE);
_paint.setStrokeWidth(lineThickness);
// _paint.setPathEffect(new DashPathEffect(new float[] { lineLength, dashGap, }, 0));
}
public DividerView(Context context) {
this(context, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getSuggestedMinimumHeight();
if(_lineHeight != height){
height = _lineHeight;
}
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(height, heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
float bottom = getHeight();
float hcenter = getWidth() * 0.5f;
canvas.drawLine(hcenter, 0, hcenter, _lineHeight, _paint); // v-line
canvas.drawLine(0, bottom, getWidth(), bottom, _paint); // h-line
}
}
사용법
activity_main.xml
<com.mytest.DividerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:dvHeight="15dp"
/>
onMeasure() 를 override 한 이유
사실 여기서는 'ㅗ' 만 그리면 되기 때문에 onDraw() 만 필요하다. 그런데 왜 onMeasure() 를 작성했느냐 하면, 기본적으로 wrap_content 로 layout_height 를 설정해 놨는데, 실제적으로 content 가 없기 때문에 실제 height 는 0 이 된다.(말이 복잡하니 그냥 넘어가자.)
여하튼 중요한 것은 DividerView 가 공간을 차지해야 보여진다. 그래서 실제로 height 가 필요하다. width 는 match_parent 이기에 0 이상의 값을 가지고 있다.
그래서 높이만 갖고 있으면 된다. 그러기 위해선 아래처럼 minHeight 를 설정해줘도 된다.
<com.mytest.DividerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="5dp"
/>
그런데 minHeight 는 좋은 design 이 아니다. 이것은 layout 의 size 이지 DividerView 의 size 가 아니기 때문이다. 그래서 이것을 app:dvHeight 로 대체했다. 그로인해 dvHeight 에서 설정한 값이 DividerView 의 height 에 반영이 되어야 했다.
그래서 onMeasure() 가 필요한 것이다. View 의 size 를 정하는 곳이 onMeasure() 이기 때문이다.(참고: Android 의 View 에서 onMeasure 와 onLayout 의 의미)
Reference
- xml - Creating horizontal and vertical dotted lines in android - Stack Overflow
출처 : http://i5on9i.blogspot.com/search?q=canvas
|