尊重原创,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/40855377
接之前的:Android自定义控件系列二:自定义开关按钮(一)和Android自定义控件系列三:自定义开关按钮(二)继续,今天要讲的就是如何在自定义控件中使用自定义属性,实际上这里有两种方法,一种是配合XML属性资源文件的方式,另一种是不需要XML资源文件的方式;下面我们分别来看看:
那么还是针对我们之前写的自定义控件:开关按钮为例来说,在之前的基础上,我们来看看有哪些属性是可以自定义的:按钮的背景图片,按钮的滑块图片,和按钮的状态(是开还是关),实际上都应该是可以在xml文件中直接定义的。
不妨先来看看之前我们在代码中不依靠自定义属性的时候,是如何写的,我们可以在initView方法中找到这样几行代码:
backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background); slideButton = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button); currentState=false;
第一步:在res/values文件夹中添加attrs.xml文件
实际上,这个文件名并不一定要写成attrs.xml,但是按照安卓源码的写法并且也便于别人查看代码的时候明确这个文件的用意,还是写成attrs.xml。
下面要如何写呢,我们还是可以参看一下安卓的源码:打开源码文件夹下\frameworks\base\core\res\res\values\attrs.xml文件,我们会发现这里面定义了很多attr的标签,里面不乏一些我们常见的属性:
<attr name="layout_width" format="dimension">
等等,在layout_width这个标签上面我们还可以发现一个
<declare-styleable name="ViewGroup_Layout">
declare-styleable标签的里包含了很多根ViewGruop相关的属性。
而在这个attrs.xml文件的最外面,是一个<resources>的标签
到这里,我们基本上就明白了一个attrs.xml文件的结构了:
首先要一个<resources>的父标签,然后里面可以包含一个declare-styleable的标签,在这个标签里面我们再定义出三个attr 标签,分别代表我们需要定义的三个属性:按钮的背景图片,按钮的滑块图片,和按钮的状态;那么剩下的一个问题就是attr标签中的format代表什么意思。实际上format代表的是这条属性的值的类型:
1.reference:参考指定Theme中资源ID,这个类型意思就是你传的值可以是引用资源
2.string:字符串,如果你想别人既能直接写值也可以用类似"@string/test"引用资源的方式,可以写成format="string|reference"
3.Color:颜色
4.boolean:布尔值
5.dimension:尺寸值
6.float:浮点型
7.integer:整型
8.fraction:百分数
9.enum:枚举 ,如果你提供的属性只能让别人选择,不能随便传入,就可以写成这样
<attr name="language">
<enum name="china" value="1"/>
<enum name="English" value="2"/>
</attr>
10.flag:位或运算
declare-styleable子元素:
定义一个styleable对象,每个styleable对象就是一组attr属性的集合 注意:这里的name属性并不是一定要和自定义类名相同,只是为了好区分对应类的属性而已
注意:上面的属性资源文件定义了该属性之后,至于到底是哪个自定义View组件中来使用该属性,该属性到底能发挥什么作用, 就不归该属性资源文件管了,也就是说这个属性资源文件是个公共的,大家都可以用,但是为了方便管理,一般都是一个自定义View里的属性写成一个declare-styleable集合.属性资源所定义的属性到底可以返回什么作用,取决于自定义组件的代码实现
在这里,我们的attrs.xml文件写成下面这样:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyToggleButton"> <attr name="current_state" format="boolean" /> <attr name="backgroundBitmap" format="reference" /> <attr name="slideButton" format="reference" /> </declare-styleable> </resources>
要如何做呢?我们先将上面给出的
backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background); slideButton = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button); currentState=false;
/*这里取得declare-styleable集合*/ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyToggleButton); /*取得本集合里面总共有多少个属性*/ int indexCount = typedArray.getIndexCount(); /*遍历这些属性,拿到属性对应的id,然后通过id拿到对应的值*/ for (int i = 0; i < indexCount; i++) { /*拿到对应的id值taId*/ int taId = typedArray.getIndex(i); switch (taId) { case R.styleable.MyToggleButton_backgroundBitmap: // drawable转bitmap backgroundBitmap = ((BitmapDrawable) typedArray .getDrawable(taId)).getBitmap(); break; case R.styleable.MyToggleButton_current_state: currentState = typedArray.getBoolean(taId, false); break; case R.styleable.MyToggleButton_slideButton: slideButton = ((BitmapDrawable) typedArray.getDrawable(taId)) .getBitmap(); default: break; } }
第三步:在布局文件中使用自定义属性,并设置属性值:
<com.example.myattrsdemo.ui.MyView android:layout_width="wrap_content" android:layout_height="wrap_content" alex:test_bitmap="@drawable/pigs" alex:test_id="1" alex:test_msg="我的自定义属性实例" />
xmlns:android="http://schemas.android.com/apk/res/android"
于是这里一个完整的布局文件写为:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:alex="http://schemas.android.com/apk/res/com.example.togglebutton" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="${relativePackage}.${activityClass}" > <com.example.togglebutton.ui.MyToggleButton android:id="@+id/my_toggle_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" alex:backgroundBitmap="@drawable/switch_background" alex:current_state="true" alex:slideButton="@drawable/slide_button" /> </RelativeLayout>
既然没有attrs.xml,那么也不需要命名空间了,我们直接在上面的布局文件中加上一句:
test_text="测试不需要XML资源文件的方式来使用自定义属性"
// 无命名空间测试 String attributeValue = attrs.getAttributeValue(null, "test_text"); System.out.println(attributeValue);
按照这个思路,上面我们定义的三个属性都可以改为不需要命名空间的方式,看起来是很方便的。但是实际上有弊端:
命名空间可以不要,属性名就要自己对应好了,不然程序取不到,不像有XML资源文件配合的方式有个约束。
至此,自定义控件三部曲就完成了。随后会加入自定义ViewGroup的内容,感谢关注!