在下水平不高,不喜勿喷,有错的地方请积极提出,谢谢
Android:自定义控件你应该知道的这些事_TypedArray
Android:自定义控件你应该知道的这些事_事件分发机制
如果想要获取Android的资源文件,我们会通过context.getresource.getXXX得到,那我们今天主要记录的是利用TypeArray获取自定义属性,比如android:layout_width="match_parent"这些,其实已经是android本身已经定义好的属性,那我们应该怎么样去创建自定义属性,又怎么样去使用自定属性呢?
1.创建自定义属性
首选创建values\attrs.xml,在attrs.xml中声明自定义属性
<declare-styleable name="MyFirstCustomerView">
<attr name="text" format="string" />
<attr name="textColor" format="color"/>
<attr name="textSize" format="dimension"/>
</declare-styleable>
- 自定义string类型,属性名为text
- 自定义color类型,属性名为textColor
- 自定义dimension类型,属性名为textSize
简单提一嘴:declare-styleable这个标签的作用其实就是可以为我们完成很多常量(int[]数组,下标常量)等的编写,简化我们的开发工作
既然是简单化,如果不使用declare-styleable标签来简单化,我们该怎么做?
首先自定义属性values\attrs.xml,如下
<resources>
<attr name="android:text" />
<attr name="text" format="string" />
<attr name="textColor" format="color"/>
<attr name="textSize" format="dimension"/>
</resources>
布局:
<com.ffcs.z.test.view.CustomView
android:layout_width="200dp"
android:layout_height="200dp"
android:text="aaaa"
app:text="@string/text"
app:textColor="@color/colorPrimaryDark"
app:textSize="18sp" />
获取自定义属性方法
private static final int[] mAttr = { android.R.attr.text,R.attr.text,R.attr.textColor,R.attr.textSize};//想要获取的attr的id
TypedArray a = context.obtainStyledAttributes(attrs, mAttr);
String android_text = a.getString(0);
String text = a.getString(a.getIndex(1));
int color=a.getColor(a.getIndex(2),textColor);
int textSize=a.getDimensionPixelSize(a.getIndex(3),20);
//输出 text = Hello world! , textAttr = 520
Log.e(TAG, "text = " + text + " , textAttr = " + text);
Log.i("TypedArray=>", "attrName_android_text:" + android_text +"\r\nattrName_text:" + text + "\r\nattrName_color:" + color + "\r\nattrName_textSize:" + textSize);
a.recycle();
Log输出:
TypedArray=>: attrName_android_text:aaaa
attrName_text:这是一个自定以空间
attrName_color:-13615201
attrName_textSize:54
format还有如下类型
format | 介绍 |
---|---|
reference | 表示引用,参考某一资源ID |
string | 表示字符串 |
color | 表示颜色值 |
dimension | 表示尺寸值 |
boolean | 表示布尔值 |
integer | 表示整型值 |
float | 表示浮点值 |
fraction | 表示百分数 |
enum | 表示枚举值 |
flag | 表示位运算 |
2.布局文件中使用自定义属性
首先需要在根布局中申明 xmlns:app="http://schemas.android.com/apk/res-auto"
<com.ffcs.z.test.view.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:text="这是自定义属性"
app:textColor="@android:color/black"
app:textSize="18sp"/>
CustomView是自定义控件,引用了app:text、app:textColor、 app:textSize="18sp"三个自定义属性
3.自定义控件CustomView
public class CustomView extends View {
public Paint paint;
private String text = "";//文本内容
private int textColor = 0xDD333333; //字体颜色
private float textSize = 20;//字体大小设置
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CustomerView);//获取TypedArray
textColor = a.getColor(R.styleable.CustomerView_textColor, textColor);//获取布局中设置的自定以颜色
textSize = a.getDimension(R.styleable.CustomerView_textSize, textSize);//获取布局中设置的自定义字体大小
text = a.getString(R.styleable.CustomerView_text);//获取布局中设置的自定义文本
paint = new Paint();//初始化 画笔
paint.setTextSize(textSize);//画笔字体大小设置
paint.setColor(textColor);//画笔的颜色
paint.setStyle(Paint.Style.FILL);//画笔风格
a.recycle();//切记:在使用TypedArray后需要回收
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(text, 100, 100, paint);
}}
-TypedArray用完一定要回收
好像丑了点,但是凑合看一下吧
了解自定义控件中构造函数的参数
Parameters | 参数解释 |
---|---|
Context | 当前上下文 |
AttributeSet | 为xml里一个节点下面的属性的集合,这个类一般都是系统在生成有xml配置的组件时生成,可以理解为当前自定义控件下的所有属性集合;提供TypedArray检索的范围 |
defStyleAttr | 在当前包含了一个引用到为TypedArray提供默认值的样式资源的theme中的一种属性。可以为0,但是为0的时候就不会再去寻找默认的;提供TypedArray检索的范围(注:这里的默认也就是defStyleRes) |
AttributeSet
讲个栗子,获取属性_字体的大小需要通过AttributeSet :
int textSize = attrs.getAttributeResourceValue(null, "textSize", 0);
if (textSize != 0) {
mEditText.setTextSize(textSize);
}
那么问题就来了,既然AttributeSet 和TypedArray都能获取到xml文件下的属性值,
直接用AttributeSet去获取xml文件下的自定义属性,为啥还要费力去初始TypedArray
去获取呢?接着看
<com.ffcs.z.test.view.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:text="@string/text"
app:textColor="@color/colorPrimaryDark"
app:textSize="18sp" />
分别输出AttributeSet和TypedArray获取到的属性值
int count = attrs.getAttributeCount();
for (int i = 0; i < count; i++) {
String attrName = attrs.getAttributeName(i);
String attrVal = attrs.getAttributeValue(i);
Log.i("attrs=>", "attrName = " + attrName + " , attrVal = " + attrVal);
}
TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CustomerView);//获取TypedArray
textColor = a.getColor(R.styleable.CustomerView_textColor, textColor);//获取布局中设置的自定以颜色
textSize = a.getDimension(R.styleable.CustomerView_textSize, textSize);//获取布局中设置的自定义字体大小
text = a.getString(R.styleable.CustomerView_text);//获取布局中设置的自定义文本
Log.i("TypedArray=>", "attrName_text:" + text + "\r\nattrName_textColor:" + textColor + "\r\nattrName_textSize:" + textSize);
输出Log
attrs=>: attrName = layout_width , attrVal = 200.0dip
attrs=>: attrName = layout_height , attrVal = 200.0dip
attrs=>: attrName = text , attrVal = @2131099685
attrs=>: attrName = textColor , attrVal = @2131427350
attrs=>: attrName = textSize , attrVal = 18.0sp
TypedArray=>: attrName_text:这是一个自定以空间
attrName_textColor:-13615201
attrName_textSize:54.0
这边我们看一下 text 用AttributeSet输出的是什么鬼,肯定用不了,那我们看一下TypedArray获取到的数值,松了一口气,瞬间明白了AttributeSet和TypedArray获取属性的区别:如果布局中属性的值是引用类型(比如:@string/text),使用AttributeSet去获得最终的字符串,那么需要第一步拿到id,第二步再去解析id,而TypedArray正是帮我们简化了这个过程。
那么有人就要问了,我们如果去获得android已经定义好了的属性,该咋整呢?举个栗子,比如上面我们都用到text,app:text和android:text,功能都一样,但是我更想要使用android:text,那么自定义组件中我改怎么去获取呢?
<declare-styleable name="test">
<attr name="android:text" />
</declare-styleable>
这里我们是使用已经定义好的属性,不需要去添加format属性,这是自定义和声明的区别
TypedArray创建
TypedArray a =getResources().obtainAttributes();
-是 Resources 的函数
TypedArray a = context.obtainStyledAttributes();
-Resources.Theme 的函数
-此方法有四个重载方法
obtainStyledAttributes(int[] attrs)
obtainStyledAttributes(int resid, int[] attrs)
obtainStyledAttributes(AttributeSet set, int[] attrs)
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
简单说,其中的参数为检索的范围 优先级xml > style > defStyleAttr > defStyleRes > theme其中3/4构造函数为最常用(PS:此处待补充)
获取自定属性正确姿势
format | 介绍 |
---|---|
string | typedArray.getString(R.styleable.xxx); |
color | typedArray.getColor(R.styleable.xxx, 默认值); |
boolean | typedArray.getBoolean(R.styleable.xxx, 默认值); |
integer | typedArray.getInteger(R.styleable.xxx, 默认值) |
float | typedArray.getFloat(R.styleable.xxx, 默认值) |
fraction | typedArray.getFraction(R.styleable.xxx, 分子, 分母,默认值) |
enum | typedArray.getInt(R.styleable.xxx, 默认值); |
flag | typedArray.getInt(R.styleable.xxx,默认值); |
dimension | sp:typedArray.getDimension(R.styleable.xxx, 20);dp:typedArray.getDimensionPixelOffset(typedArray.getIndex(R.styleable.xxx), 20); 或:private float radius = 3; radius=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,radius,getResources().getDisplayMetrics());radius = typedArray.getDimension(R.styleable.xxx, normalRadius); |
总结
- declare-styleable标签可以为我们完成很多常量(int[]数组,下标常量)等的编写,简化我们的开发工作,可以不声明,但是需要在自定义控件中,声明引用自定义属性数组
- TypedArray 可有obtainAttributes()、obtainStyledAttributes()方法创建,常用obtainStyledAttributes(int resid, int[] attrs)构造方法
- TypedArray和AttributeSet区别在于,布局中引用参数为id时的不同(@string/text),所获取的值不同
- format如果为dimension时,注意:sp和dp需要转化
此文部分理解于:
【张鸿洋的博客】Android 深入理解Android中的自定义属性