自定义属性

有以下几个步骤:

自定义一个CustomView(extends View )类
编写values/attrs.xml,在其中编写styleable和item等标签元素
在布局文件中CustomView使用自定义的属性(注意namespace)
在CustomView的构造方法中通过TypedArray获取
自定义属性的声明文件,在res/values 目录下新建一个 attrs.xml文件
如要用系统定义过的android:text"属性,不需要写format
可以看一下系统中自定义属性的文件 Sdk/platforms/android-xx/data/res/values/attrs.xml

有多个styleable都要用到的共同的属性,在resources开头进行定义,后续引用只需要引用名字就可以了
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="textColor" format="color"/>
<attr name="textSize" format="dimension"/>
1
2
3
4
使用系统原有的属性时,在前面加上android命名
<declare-styleable name="title_attrs">
<!--尺寸值,格式是dimension-->
<attr name="width" format="dimension"/>
<attr name="height" format="dimension"/>
<attr name="textColor"/>
<attr name="textSize"/>
<!--声明需要使用系统定义过的text属性,注意前面需要加上android命名-->
<attr name="android:text"/>
</declare-styleable>

<declare-styleable name="RectangleView">
<attr name="textColor"/>
<attr name="textSize"/>
<attr name="android:text"/>
</declare-styleable>

</resources>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在布局文件中对应的去用
首先需要加上一个命名空间xmlns:title="http://schemas.android.com/apk/res-auto"
然后直接利用这个命名空间title设置属性即可
<com.sky.customapplication.TitleView
android:id="@+id/title_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
title:textColor="#000"
title:textSize="26sp"
android:text="im text">

</com.sky.customapplication.TitleView>
1
2
3
4
5
6
7
8
9
在自定义控件代码中获取各属性
R.styleable.RectangleView是刚刚attrs文件中的name

TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RectangleView, defStyleAttr, 0);
//mText = array.getString(R.styleable.RectangleView_android_text);
mTextColor = array.getColor(R.styleable.RectangleView_textColor, Color.BLACK);
mTextSize = array.getDimensionPixelSize(R.styleable.RectangleView_textSize, 40);
array.recycle(); //注意回收
1
2
3
4
5
onDraw()
实现三个构造方法,在第三个构造方法中进行初始化、解析自定义属性的值
初始化笔刷,mBounds是绘制时控制文本绘制范围的长方形
public class RectangleView extends View implements View.OnClickListener {

private Paint mPaint;
private Rect mBounds;
//private String mText;
private float mTextSize;
private int mTextColor;
private int mCount;
private String text;

public RectangleView(Context context) {
this(context, null);
}

public RectangleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public RectangleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//新建画笔
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //抗锯齿
mBounds = new Rect();

//加载自定义属性集合
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RectangleView, defStyleAttr, 0);
// 将解析的属性传入到画笔颜色变量当中(本质上是自定义画笔的颜色)
// 第二个参数是默认设置颜色(即无指定color情况下使用)
//mText = array.getString(R.styleable.RectangleView_android_text);
mTextColor = array.getColor(R.styleable.RectangleView_textColor, Color.BLACK);
mTextSize = array.getDimensionPixelSize(R.styleable.RectangleView_textSize, 40);

array.recycle(); //记得回收

setOnClickListener(this);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
在onDraw中绘制
@Override
protected void onDraw(Canvas canvas) {
//画笔颜色
mPaint.setColor(Color.YELLOW);
//画一个长方形
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
//设置画字的颜色
mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
text = String.valueOf(mCount);
mPaint.getTextBounds(text, 0, text.length(), mBounds);
float textWidth = mBounds.width();
float textHeight = mBounds.height();
//文字绘制的起点是从文字的左下角开始的,实际看见文字的Y坐标需要加上文字的自身高度
canvas.drawText(text, getWidth()/2 - textWidth/2, getHeight()/2 + textHeight/2, mPaint);
}

@Override
public void onClick(View v) {
mCount++;
invalidate(); //视图重绘,onDraw调用
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在布局中引用
<com.sky.customapplication.RectangleView
android:layout_width="200dp"
android:layout_height="100dp"
title:textColor="#00FF33"
title:textSize="30sp"
android:padding="15dp"
/>
1
2
3
4
5
6
7


手动支持wrap_content属性
但是此时,如果设置layout_width和layout_height 属性为 wrap_content,并不会适应自身大小,而是填满父控件,和match_parent效果相同。
这是因为使用系统的onMeasure方法时,系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果;而当我们设置为WRAP_CONTENT系统帮我们测量的结果也是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法:

posted @ 2019-09-10 17:23  李艳艳665  阅读(1118)  评论(0编辑  收藏  举报