您的位置:首页 > 移动开发 > Android开发

Android应用资源总结八: 自定义属性获取值的过程解惑

2017-10-12 22:16 525 查看
  在自定义View的时候,一般都会自定义属性,然后在xml中定义属性值,接着在代码中获取属性值,简单的流程如下:

1.在attrs.xml中定义属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="test">
<attr name="android:text"/>
<attr name="android:layout_width"/>
<attr name="text" format="string" />
<attr name="testAttr" format="integer" />
</declare-styleable>
</resources>


说明:
android:text
android:layout_width
是android系统定义的属性,我们若使用只要:

<attr name="android:text"/>
<attr name="android:layout_width"/>


不需要设置format。

2.自定义View类

package com.example.test;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class CustomerTextView extends TextView{

public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test);

String text = ta.getString(R.styleable.test_text);
int textAttr = ta.getInteger(R.styleable.test_textAttr, -1);
ta.recycle();
}

}


3.在布局文件中定义属性值

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<com.example.test.CustomerTextView
android:layout_width="100dp"
android:layout_height="200dp"
android:text = "customer text"
app:testAttr="520"
app:text="helloworld" />

</RelativeLayout>


大致的流程就是这样。

现在有几个问题:

1. 在构造函数public CustomerTextView(Context context, AttributeSet attrs)中AttributeSet是什么

2. R.styleable.test是什么

3. TypedArray是什么

4. R.styleable.test_text和R.styleable.test_textAttr是什么

下面来分析下:

1.AttributeSet是什么

直接打印出来看看:

public CustomerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
int count = attrs.getAttributeCount();
for(int i = 0;i < count;i++)
{
String name = attrs.getAttributeName(i);
String value = attrs.getAttributeValue(i);
int id = attrs.getAttributeNameResource(i);
Log.e("ATTR","name = "+name+",value = "+value+",id = "+id);
}
}


运行结果如下:

ATTR: name = layout_width,value = 100.0dip,id = 16842996
ATTR: name = layout_height,value = 200.0dip,id = 16842997
ATTR: name = text,value = helloworld,id = 2130772242
ATTR: name = testAttr,value = 520,id = 2130772243


结合布局文件,发现这些正是布局文件中定义的属性,name是属性名,value是属性值,id则是各个属性在R文件的中的id,有事实为证,

查找在R.java,找到:

public static final int testAttr=0x7f010113;//10进制为2130772243
public static final int text=0x7f010112;//10进制为2130772242


所以从以上分析,AttributeSet存储的是View在xml定义的属性的信息,包括属性的id号,属性名称,属性值。

2.R.styleable.test是什么

也是打印来看看:

public CustomerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
for(int i = 0;i < R.styleable.test.length;i++)
{
Log.e("ATTR"," R.styleable.test["+i+"] = "+R.styleable.test[i]);
}
}


运行结果如下:

ATTR:  R.styleable.test[0] = 16842996
ATTR:  R.styleable.test[1] = 16843087
ATTR:  R.styleable.test[2] = 2130772242
ATTR:  R.styleable.test[3] = 2130772243


对应R.java文件,上面四个值是属性的id号,这个正是我们在attrs.xml里面的自定义属性,正好一一对应:

<declare-styleable name="test">
<attr name="android:text"/>
<attr name="android:layout_width"/>
<attr name="text" format="string" />
<attr name="testAttr" format="integer" />
</declare-styleable>


也就是说R.styleable.test是一个数组,存储着test自定义列表的全部属性的id号

3.TypedArray是什么

同样也是打印看看:

public CustomerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.test);
Log.e("ATTR","ta count = "+ta.getIndexCount());

String text = ta.getString(R.styleable.test_text);
int textAttr = ta.getInteger(R.styleable.test_testAttr, -1);

ta.recycle();
}


运行结果如下:

ATTR: ta count = 4


我修改布局xml文件,去掉android:text属性:

<com.example.test.CustomerTextView
android:layout_width="100dp"
android:layout_height="200dp"
app:testAttr="520"
app:text="helloworld" />


再次运行:

ATTR: ta count = 3


我再依次去掉app:testAttr和app:text属性,运行后打印的值递减,

说明TypedArray存储着一组属性信息,这些属性在R.styleable.test列表中,且要在xml文件中定义,即R.styleable.test中有四个属性,然后去AttributeSet列表中寻找看这四个属性那些有出现在列表中(即有在xml中定义),然后通过obtainStyledAttributes()加载到ypedArray中。

4.R.styleable.test_text和R.styleable.test_textAttr是什么

打印看:

ATTR: R.styleable.test_text = 2,R.styleable.test_testAttr = 3


对应如下自定义属性的第2和第3个:

<declare-styleable name="test">
<attr name="android:text"/>
<attr name="android:layout_width"/>
<attr name="text" format="string" />
<attr name="testAttr" format="integer" />
</declare-styleable>


说明R.styleable.test_text和R.styleable.test_testAttr是索引,用这个索引去TypedArray中获取对应属性的属性值:

String text = ta.getString(R.styleable.test_text);
int textAttr = ta.getInteger(R.styleable.test_testAttr, -1);


简单的说就是:

1.AttributeSet存储所有定义在xml中的属性的id号,属性名,属性值(包括系统定义的属性如android:layout_height)

2.R.styleable.test存储test这个自定义属性列表里面属性的id号

3.TypedArray存储test自定义属性列表在xml中赋值的属性的信息

4.R.styleable.test_text和R.styleable.test_textAttr是索引号
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android