目录
1. attr 自定义属性的类型
<attr name="字符串" format="string"/>
<attr name="颜色" format="color"/>
<attr name="尺寸" format="dimension"/>
<attr name="整型" format="integer"/>
<attr name="浮点型" format="float"/>
<attr name="布尔型" format="boolean"/>
<attr name="资源引用" format="reference"/>
<attr name="百分数" format="fraction"/>
<attr name="枚举">
<enum name="name0" value="0"/>
<enum name="name1" value="1"/>
</attr>
<attr name="立死亡flag">
<flag name="name0" value="0"/>
<flag name="name1" value="1"/>
<flag name="name2" value="2"/>
</attr>
<attr name="获取多种类型 | 号隔开" format="reference|color|integer"/>
2. 声明自定义属性
<attr name="iconWidth" format="dimension"/>
<attr name="iconHeight" format="dimension"/>
attr 标签属性会在R类下的attr类中生成16进制地址静态常量,比如:
public static final class attr {
public static final int iconWidth = 0x7f010000;
public static final int iconHeight = 0x7f010001;
}
代码中取属性值方法:
int[] attrKeys = {R.attr.iconWidth, R.iconHeight};
TypedArray typedArray = context.obtainStyledAttributes(set, atttrKeys);
float iconWidth = typedArray.getDimension(0, defaultValue);
float iconHeight = typedArray.getDimension(1, defaultValue);
declare-styleable 标签封装 attr
<declare-styleable name="MyIconView">
<attr name="iconWidth" format="dimension"/>
<attr name="iconHeight" format="dimension"/>
</declare-styleable>
使用declare-styleable封装的attr会在R类下的styleable类封装attr类下的16进制地址生成int[]数组,并生成下标索引:
public static final class styleable {
public static final int[] MyIconView = {
0x7f010000, 0x7f010001
};
public static final int MyIconView_iconWidth = 0;
public static final int MyIconView_iconHeight = 1;
}
代码中取属性值方法:
TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.MyIconView);
float iconWidth = typedArray.getDimension(R.styleable.MyIconView_iconWidth, defaultValue);
float iconHeight = typedArray.getDimension(R.styleable.MyIconView_iconHeight, defaultValue);
3. 自定义属性复用
重复的自定义属性:
<declare-styleable name="MyIconView">
<attr name="icon" format="reference"/>
<attr name="iconWidth" format="dimension"/>
<attr name="iconHeight" format="dimension"/>
</declare-styleable>
<declare-styleable name="MyImageView">
<attr name="icon" format="reference"/>
</declare-styleable>
复用自定义属性写法:
<attr name="icon" format="reference"/>
<declare-styleable name="MyIconView">
<attr name="icon"/>
<attr name="iconWidth" format="dimension"/>
<attr name="iconHeight" format="dimension"/>
</declare-styleable>
<declare-styleable name="MyImageView">
<attr name="icon"/>
</declare-styleable>
复用Android SDK已有属性:
<declare-styleable name="MyIconView">
<attr name="android:src"/>
<attr name="iconWidth" format="dimension"/>
<attr name="iconHeight" format="dimension"/>
</declare-styleable>
4. 自定义属性之坑
Caused by: java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x1f
不能定义名称为 SDK 的自定义属性名:
<!-- sdk attr -->
android:text
android:textSize
android:textColor
<!-- 自己定义的属性不能定义成上面的属性,不能定义如下 -->
<attr name="text" format="string"/>
<attr name="textSize" format="dimension"/>
<attr name="textColor" format="color"/>
5. XML 布局文件中使用自定义属性——命名空间
- 系统的命名空间:xmlns:android="http://schemas.android.com/apk/res/android"
通用命名空间:
xmlns:app="http://schemas.android.com/apk/res-auto"
包名命名空间:
xmlns:app="http://schemas.android.com/apk/res/包名"
xmlns:app 是自定义的属性引用名, URL:http://schemas.android.com/apk/res 是默认的资源标识,实际是不可访问的
命名空间作用域:声明到根布局则全局使用,声明到单个 View 则只能在单个 View 内使用
属性的使用 :
<com.bin.MyIconView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
app:iconWidth="35dp"
app:iconHeight="35dp" />
android:src 的 : 号是转意的语法,左边的名称是来自哪个命名空间的属性.
6. 使用 style 复用 xml 属性
重复属性:
<com.bin.MyIconView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_launcher"
app:iconWidth="35dp"
app:iconHeight="35dp" />
<com.bin.MyIconView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/ic_launcher"
app:iconWidth="35dp"
app:iconHeight="35dp" />
封装style:
<style name="MyIconView">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1"</item>
<item name="android:src">@drawable/ic_launcher</item>
<item name="iconWidth">35dp</item>
<item name="iconHeight">35dp</item>
</style>
注意:SDK的属性需要android:,自定义的属性直接写名字
复用属性后:
<com.bin.MyIconView
style="@style/MyIconView" />
<com.bin.MyIconView
style="@style/MyIconView" />
7. 属性优先级
7.1 View的构造方法
public View(Context context) {
this(context, null);
}
public MyCustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
this(context, attrs, defStyle, 0);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyle, int defStyleRec) {
super(context, attrs, defStyle, defStyleRec);
// TODO:获取自定义属性
}
- 4个参数的构造方法是API21引入,若有需求请注意版本兼容,一般3个参数的构造方法可以满足需求
- 代码中 new ,调用第一个构造方法。
- XML 中调用第二个构造方法。
- 第三和第四个构造方法需要手动调用。
7.2 TypedArray
context 中返回 TypedArray 的四个方法
- obtainAttributes(AttributeSet set, int[] attrs) //从layout设置的属性集中获取attrs中的属性
- obtainStyledAttributes(int[] attrs) //从系统主题中获取attrs中的属性
- obtainStyledAttributes(int resId,int[] attrs) //从资源文件定义的style中读取属性
- obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
参数含义:
- AttributeSet set:从layout xml文件为view添加的属性集合。(键值)
- int[] attrs:每个方法都有的参数。最终返回的TypedArray只能查找对应数组Id的属性。(键)
- int defStyleAttr:从当前Activity设置的Theme中搜索的style。(键值)
- int defStyleRes:备用style,当defStyleAttr为0时,并且them中未设置对应此View的defStyleAttr才生效。(键值)
- int resId:直接从资源文件中定义的某个style中读取。(键值)
优先级:
- 布局中为View显示设置的值 >
- 布局中style指定的样式 >
- (defStyleAttr) 布局通过主题中配置的style,代码中指定的style resId >
- (defStyleRes) 代码中指定的style resId。当defStyleAttr为0时,并且them中未设置对应此View的defStyleAttr才生效 >
- theme中指定的item attr属性
7.3 全局Theme与局部Theme优先级
Application Theme < Activity Theme < View style: 三个theme设置了共同属性而值不同的优先级。
例如 TextView 的 android:textColor:
// layout
<LinearLayout ...>
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#0080FF" />
</LinearLayout>
// style
<!-- Activity Theme -->
<style name="ActivityTextColor">
<item name="android:textColor">@android:color/white</item>
</style>
<!-- Application Theme -->
<style name="ApplicationTextColor">
<item name="android:textColor">@android:color/black</item>
</style>
结果:
控件ID:tv1 textColor = white
控件ID:tv2 textColor = #0080FF
参考:深入理解Android 自定义attr Style styleable以及其应用