- 第一步,在 values 目录下面创建自定义属性的 XML,比如 attrs.xml 或 attrs_ 开头的文件名,当然文件名没有什么限制,本例选择创建 attrs.xml 文件。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleView">
<attr name="circle_color" format="color"/>
</declare-styleable>
</resources>
声明属性集合 CircleView ,集合里可以有很多自定义属性,format 有多种格式,reference 指资源 id,dimension 指尺寸,string、integer、boolean 指基本类型。
- 第二步,在 View 的构造方法中解析自定义属性值并做相应处理,解析 cricle_color 属性的值,代码如下:
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
mColor = a.getColor(R.styleable.CircleView_circle_color, Color.RED);
a.recycle();
}
首先加载自定义属性集合 CircleView ,接着解析 CircleView 属性集合中 circle_color 属性,解析完要调用 recycle 方法释放资源。
- 第三步,在布局文件中使用自定义属性,如下所示:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".view.ViewActivity">
<com.example.sunshinexu.view.CircleView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_margin="20dp"
android:padding="20dp"
app:circle_color="#00ff00"
</LinearLayout>
为了使用自定义属性,必须在布局文件中添加 schemas 声明:xmlns:app=”http://schemas.android.com/apk/res-auto” 。app 是自定义属性的前缀,可以换其他的名字,apk 后可以用 res/附加应用的包名。
- 下面是 自定义View,CircleView 完整代码,要对 wrap_content 做特殊处理,为什么做处理,看我上一篇博客,View 的工作原理。
public class CircleView extends View {
private static final String TAG = "CircleView";
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int mColor = Color.RED;
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
mColor = a.getColor(R.styleable.CircleView_circle_color, Color.RED);
a.recycle();
init();
}
public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(400,200);
} else if (widthMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(400,heightSize);
} else if (heightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSize,200);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
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);
}
private void init() {
mPaint.setColor(mColor);
}
}