在我们通常的写自定义View的时候,一定要注意如下几个点.
1. 让View支持warp_content,通过在onMeasure中设置MeasureSpec来实现
2. 如果有必要,让你的View支持padding,在onDraw中实现,如果是ViewGroup则要在onMeasure和onLayout中考虑自己的padding和子元素的margin的影响
3. 尽量不要在View中使用Handler,使用View的post方法即可
4. View中如果有线程或者动画,需要及时停止,在onDetachFromWindow是一个很好的时机
5. View带有滑动嵌套情形时,需要处理好滑动冲突
下面给出一个简单例子
这里贴出View部分的代码
public class CricleView extends View {
private int mColor = Color.RED;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public CricleView(Context context) {
this(context, null);
}
public CricleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CricleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//这里处理自定义属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CricleView);
mColor = a.getColor(R.styleable.CricleView_circle_color, Color.RED);
a.recycle();
init();
}
private void init() {
mPaint.setColor(mColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
//这里分三种情况设置的是wrap_content默认的大小为200px
if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(200, 200);
}else if(widthSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(200, heightSpecSize);
}else if(heightSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(widthSpecSize, 200);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//这里处理View的padding属性
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int width = getWidth() - paddingLeft - paddingRight;
int height = getHeight() - paddingTop - paddingBottom;
int radius = Math.min(width, height) / 2;
canvas.drawCircle(paddingLeft + width / 2, paddingTop + height / 2, radius, mPaint);
}
}
当然要定义自定义属性需要在Value目录下建一个attrs开头的xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CricleView">
<attr name="circle_color" format="color"/>
</declare-styleable>
</resources>
在布局文件里面要写上命名空间
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
>
<com.tom.view.CricleView
app:circle_color="#000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>