1, 简介
一般来说,我们进行自定义View,但除非使用Android 原生的 XML属性,我们想添加自定义的XML属性来扩展自定义View的复用性。
2, 实现流程
- 编写 values/attrs.xml, 在其中进行编译 styleable 和 item 等标签元素;
- 自定义一个CustomView类(继承View或者其子类);
- 在布局文件中使用CustomView进行布局并使用自定义的属性(注:xmlns(XML命名空间));
- 在 CustomView的构造方法中通过 TypedArray获取;
3, 实现Damo
a) values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="steven">
<attr name="text" format="string" />
<attr name="testAttr" format="integer" />
</declare-styleable>
</resources>
b) 布局文件 main.xml
<?xml version="1.0" encoding="utf-8"?>
<!--com.example.yufen.learnapplication为-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:zyf="http://schemas.android.com/apk/res/com.example.yufen.learnapplication"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--注: xmlns:zyf="http... 为 XML命名空间,必须添加;com.example.yufen.learnapplication则为该应用程序的Package Name;但Android Studio推荐统一使用: xmlns:zyf="http://schemas.android.com/apk/res-auto"-->
<com.example.yufen.learnapplication.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
zyf:testAttr="520"
zyf:text="HelloWord"/>
</LinearLayout>
c) 自定义View:
package com.example.yufen.learnapplication;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* Created by Yufen on 2016/6/6.
*/
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
//将steven的styleable的属性的值进行统一读取出来
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.steven);
//steven_testAttr为 styleable的名字 + _ + 自定义属性的名字
int textAttr = ta.getInteger(R.styleable.steven_testAttr, -1);
String text = ta.getString(R.styleable.steven_text);
setText("text = " + text + " , textAttr = " + textAttr);
//释放回收
ta.recycle();
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
4, AttributeSet与TypedArray
AttributeSet中保存的是该View声明的所有的属性,并且外面的确可以通过它去获取(自定义的)属性;
int count = attrs.getAttributeCount();
for (int i = 0; i < count; i++) {
String attrName = attrs.getAttributeName(i);
String attrVal = attrs.getAttributeValue(i);
Log.e("yufen", "attrName = " + attrName + " , attrVal = " + attrVal);
}
但如果 布局是这样定义时(android:layout_height=”@dimen/dp200”), AttributeSet中获取的值 为 @2131165235, 我们则需要下面的才能读取其值:
int widthDimensionId = attrs.getAttributeResourceValue(0, -1);
Log.e("yufen", "layout_width="+getResources().getDimension(widthDimensionId));
而我们可直接通过 TypedArray来简捷读取内容:
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.steven);
int textAttr = ta.getInteger(R.styleable.steven_testAttr, -1);
String text = ta.getString(R.styleable.steven_text);
总结:AttributeSet 的作用就是在控件进行初始化的时候,解析布局文件中该控件的属性(key eg:background)与该值(value eg:@drawable/icon)的信息封装在AttributeSet中,传递给该控件(View)的构造函数。对于非Android自带的属性,在View类中处理时是无法识别的,因此需要我们自己解析。所以这就要用到另外一个类TypedArray。在AttributeSet中我们有属性名称,有属性值,但是控件如何知道哪个属性代表什么意思呢?这个工作就由TypedArray来做了。TypedArray对象封装了/values/attrs.xml中的styleable里定义的每个属性的类型信息,通过TypedArray我们就可以知道AttributeSet中封装的值到底是干什么的了,从而可以对这些数据进行应用。
5, Declare-styleable用法
1) Declare-styleable用法详解请直接参考: Android 自定义属性用法详解
2) Damo:
a) attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="steven">
<!--字符串-->
<attr name="text" format="string" />
<!--整型值-->
<attr name="testAttr" format="integer" />
<!--参考某一资源ID-->
<attr name="my_backgroud" format="reference" />
<!--颜色值-->
<attr name="my_textColor" format="color" />
<!--布尔值-->
<attr name="my_clickable" format="boolean" />
<attr name="my_width" format="dimension" />
<!--浮点值-->
<attr name="my_alpha" format="float" />
<!--百分数-->
<attr name="my_pivotX" format="fraction" />
<!--枚举值-->
<attr name="my_orientation" >
<enum name="horizontal" value="0" />
<enum name="vertical" value="1"/>
</attr>
<!--位或运算-->
<attr name="my_windowSoftInputMode">
<flag name = "stateUnspecified" value = "0" />
<flag name = "stateUnchanged" value = "1" />
<flag name = "stateHidden" value = "2" />
<flag name = "stateAlwaysHidden" value = "3" />
<flag name = "stateVisible" value = "4" />
<flag name = "stateAlwaysVisible" value = "5" />
<flag name = "adjustUnspecified" value = "0x00" />
<flag name = "adjustResize" value = "0x10" />
<flag name = "adjustPan" value = "0x20" />
<flag name = "adjustNothing" value = "0x30" />
</attr>
</declare-styleable>
</resources>
b) main.xml
<?xml version="1.0" encoding="utf-8"?>
<!--com.example.samsung.learnapplication为-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:zyf="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<!---->
<com.example.yufen.learnapplication.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
zyf:text="HelloWord"
zyf:testAttr="520"
zyf:my_backgroud="@drawable/send_music_thumb"
zyf:my_textColor="#F5F5F5"
zyf:my_clickable="true"
zyf:my_width="200dp"
zyf:my_alpha="0.9"
zyf:my_pivotX="65%"
zyf:my_orientation="horizontal"
zyf:my_windowSoftInputMode="stateAlwaysHidden|stateAlwaysVisible|adjustNothing"
/>
</LinearLayout>
c) 自定义View 解析自定义属性值 :
package com.example.yufen.learnapplication;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
/**
* Created by Yufen Zhi on 2016/6/6.
*/
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
//
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.steven);
//steven_testAttr为 styleable的名字 + _ + 自定义属性的名字
int textAttr = ta.getInteger(R.styleable.steven_testAttr, -1);
String text = ta.getString(R.styleable.steven_text);
Drawable drawable = ta.getDrawable(R.styleable.steven_my_backgroud);
int color = ta.getColor(R.styleable.steven_my_textColor, 0xFFFFF);
boolean clickable = ta.getBoolean(R.styleable.steven_my_clickable, false);
float width = ta.getDimension(R.styleable.steven_my_width, 0);
float alpha = ta.getFloat(R.styleable.steven_my_alpha, 0.0f);
float pivotX = ta.getFraction(R.styleable.steven_my_pivotX, 1, 1, 0);
int orientation = ta.getInteger(R.styleable.steven_my_orientation, -1);
int windowSoftInputMode = ta.getInteger(R.styleable.steven_my_windowSoftInputMode, 0);
String windowSoftInputMode_string = ta.getString(R.styleable.steven_my_windowSoftInputMode);
//释放回收
ta.recycle();
Log.d("yufen","text = " + text + ", textAttr = " + textAttr + ", drawable = " + drawable + ", color= " + color + ", clickable = " + clickable + ", width = " + width + ",alpha = " + alpha + ", pivotX = " + pivotX + ", orientation = " + orientation + ", windowSoftInputMode = " + windowSoftInputMode + ", windowSoftInputMode_string = " + windowSoftInputMode_string);
}
}
d) 得到的结果为:
06-07 13:49:55.561 21946-21946/? D/yufen: text = HelloWord, textAttr = 520, drawable = android.graphics.drawable.BitmapDrawable@301ef41, color= -657931, clickable = true, width = 700.0,alpha = 0.9, pivotX = 0.65, orientation = 0, windowSoftInputMode = 55, windowSoftInputMode_string = 0x37
特别要注意: 属性定义时可以指定多种类型值。
<declare-styleable name = "名称">
<attr name = "background" format = "reference|color" />
</declare-styleable>