本文作为自定义View的初步实践,取材自《android开发艺术探索》
目录效果如下方法activity_main.xmlattr.xml属性CircleView重写onDraw()重写onMeasure()java源代码 效果如下 方法 activity_main.xml这是我们自己设计的CircleView控件,其在xml中如下表示
其中
xmlns:app="http://schemas.android.com/apk/res-auto"
表示自定义属性,使得我们可以在CircleView中使用
app:circle_color="#FFFF00"
那circle哪来的呢?这里我们要为CircleView构建属于自己的attr.xml属性
attr.xml属性在values新建attr.xml
写上
其中资源为styleable ,和id,layout同级,名字为CircleView,这里我们定义的属性名为circle_color,属性是color,当然也可以定义其他format
CircleView接下来再在新建的CircleView类中取到color,在构造方法中
public CircleView(Context context, AttributeSet attributeSet) {
super(context,attributeSet);
TypedArray a = context.obtainStyledAttributes(attributeSet,R.styleable.CircleView);
mColor = a.getColor(R.styleable.CircleView_circle_color, Color.RED);
a.recycle();
Log.d(TAG, "CircleView: Second");
init();
}
private void init() {
mPaint.setColor(mColor);
}
用TypedAtrray获取,如图
然后我们再将已经获取颜色的Paint用canvas画出圆形,重写onDraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingLeft();
int paddingTop = getPaddingLeft();
int paddingBottom = getPaddingLeft();
int width = getWidth() - paddingLeft - paddingRight; //缩减宽高
int height = getHeight() - paddingTop - paddingBottom;
int radius = Math.min(width,height)/2;
canvas.drawCircle(width/2+paddingLeft,height/2+paddingBottom,radius,mPaint);
}
这里我们画了很大的精力取计算Padding,因为我们在activity_main中设置了padding,但是自定义控件默认是不支持的,所以我们要自己改,具体是将width左右都减小padding,由于我们的圆心是由width和height决定,为了不影响圆心位置,我们在画的时候加上一个padding即可,这样看起来就是画的圆形两边都缩小了,但是位置不变
重写onMeasure()另外一个需要重写的是onMeasure(),主要用来做尺寸的测量,因为我们在activity_main中设置了wrap_content,但是自定义控件不知道wrap_content是多少,只当match_content,所以我们要在这里设定
@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);
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);
}
}
这里默认设置成200
java源代码package com.example.makeview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class CircleView extends View {
final String TAG = "CircleView";
private int mColor =Color.RED;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public CircleView(Context context) {
super(context);
Log.d(TAG, "CircleView: First");
init();
}
public CircleView(Context context, AttributeSet attributeSet) {
super(context,attributeSet);
TypedArray a = context.obtainStyledAttributes(attributeSet,R.styleable.CircleView);
mColor = a.getColor(R.styleable.CircleView_circle_color, Color.RED);
a.recycle();
Log.d(TAG, "CircleView: Second");
init();
}
public CircleView(Context context, AttributeSet attributeSet, int defStyleAttr) {
super(context, attributeSet, defStyleAttr);
Log.d(TAG, "CircleView: Third");
init();
}
private void init() {
mPaint.setColor(mColor);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingLeft();
int paddingTop = getPaddingLeft();
int paddingBottom = getPaddingLeft();
int width = getWidth() - paddingLeft - paddingRight; //缩减宽高
int height = getHeight() - paddingTop - paddingBottom;
int radius = Math.min(width,height)/2;
canvas.drawCircle(width/2+paddingLeft,height/2+paddingBottom,radius,mPaint);
}
@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);
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);
}
}
}