android 自定义控件 使用declare-styleable进行配置属性(源码角度)
最近在模仿今日头条,发现它的很多属性都是通过自定义控件并设定相关的配置属性进行配置,于是便查询了解了下declare-styleable,下面我把自己的使用感受和如何使用进行说明下。
declare-styleable:declare-styleable是给自定义控件添加自定义属性用的。
官方的相关内部控件的配置属性文档:http://developer.android.com/reference/android/R.styleable.html
如果不知道如何查看源码:点击这里
起初,在自定义控件的时候,会要求构造3个方法中的一个或多个,好比我自定义的控件PersonView,
- public PersonView(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
- }
- public PersonView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- // TODO Auto-generated constructor stub
- }
- public PersonView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
public PersonView(Context context) {
super(context);
// TODO Auto-generated constructor stub
} public PersonView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
} public PersonView(Context context, AttributeSet attrs) {
super(context, attrs);
}
其中的AttributeSet attrs一般都没给它配置和使用,所以不知道这个东西到底怎么用,后来查看源码发现,这个配置在默认情况下使用的是系统自己的默认配置,一旦你直接设定了它的属性,默认属性就会被你的赋值所替代。
下面我们拿TextView的源码看看AttributeSet是如何进行操作的。
初始化时候,在布局文件中写android:text="拉拉";
初始化TextView的时候,它的类中的属性都会初始化;
接着往下看,你可以看到以下代码:
- TypedArray a = theme.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);
- TypedArray appearance = null;
- int ap = a.getResourceId(
- com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
- a.recycle();
- if (ap != -1) {
- appearance = theme.obtainStyledAttributes(
- ap, com.android.internal.R.styleable.TextAppearance);
TypedArray a = theme.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);
TypedArray appearance = null;
int ap = a.getResourceId(
com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
a.recycle();
if (ap != -1) {
appearance = theme.obtainStyledAttributes(
ap, com.android.internal.R.styleable.TextAppearance);
这个就是系统在默认的资源文件R.styleable中去获取相关的配置。
如果appearance不为空,它就会去寻找获取相关属性,接着往下看。
此时的text = ""; 就是准备输出的字符串初始化。
之后它便会查找你布局文件XML中是否设定给了它text属性值
之前我们设定过android:text="拉拉"; 所以它便会得到相关的赋值,之后调用
- <span style="font-size:18px;"> setText(text, bufferType);
- if (hint != null) setHint(hint);
- </span>
<span style="font-size:18px;"> setText(text, bufferType);
if (hint != null) setHint(hint);
</span>
输出该字符串。当资源检查赋值完毕后,调用a.recycle();释放。 同理也可以发现,像hint,textcolor这类属性都是这么初始化赋值的。
思路:
自定义控件并且自定义属性的情况下,你可以通过这样去获取判断是否配置了相关的属性,并进行赋值操作。
从源码那边我们大体知道了一个控件的属性配置和初始化流程,下面就让我们按照这个思路去自己学习下如何自定义配置。
下面我要写一个继承了TextView的PersonView类,给它设定属性配置,之后实现属性的显示。
1.首先,先写attrs.xml
在res-vlaues文件夹下创建资源文件attrs.xml或则自定义一个资源文件xx.xml,都可以。
之后在里面配置declare-styleable ,name为PersonAttr
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="PersonAttr">
- <attr name="name" format="reference" />
- <attr name="sex" format="reference" />
- <attr name="age" format="integer" />
- <attr name="weight">
- <flag name="fat" value="2" />
- <flag name="mid" value="1" />
- <flag name="thin" value="0" />
- </attr>
- <attr name="adult" format="boolean" />
- <attr name="textSize" format="dimension" />
- </declare-styleable>
- </resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="PersonAttr">
<attr name="name" format="reference" />
<attr name="sex" format="reference" />
<attr name="age" format="integer" />
<attr name="weight">
<flag name="fat" value="2" />
<flag name="mid" value="1" />
<flag name="thin" value="0" />
</attr>
<attr name="adult" format="boolean" />
<attr name="textSize" format="dimension" />
</declare-styleable>
</resources>
我这里设置了姓名name,性别sex,年龄age,以及特征属性weight(fat,mid,thin内部的3个属性及对应的属性值),还有是否成年adult,和TextView的字体大小textView。
可能这里有人会问,format是什么,里面的单词代表的又是什么意思。
format就是格式,里面的就是这个属性对应的格式,下面列出来大致的格式有:
1. reference:参考某一资源ID,以此类推
(1)属性定义:
<declare-styleable name = "名称">
<attr name = "background" format = "reference" />
</declare-styleable>
(2)属性使用:
<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/图片ID"
/>
2. color:颜色值
<declare-styleable name = "名称">
<attr name = "textColor" format = "color" />
</declare-styleable>
3. boolean:布尔值
<declare-styleable name = "名称">
<attr name = "focusable" format = "boolean" />
</declare-styleable>
4. dimension:尺寸值。注意,这里如果是dp那就会做像素转换
<declare-styleable name = "名称">
<attr name = "layout_width" format = "dimension" />
</declare-styleable>
5. float:浮点值。
6. integer:整型值。
7. string:字符串
8. fraction:百分数。
9. enum:枚举值
10. flag:是自己定义的,类似于 android:gravity="top",就是里面对应了自己的属性值。
12.reference|boolean:布尔值的资源文件
注意://由于reference是从资源文件中获取:所以在XML文件中写这个属性的时候必须 personattr:name="@string/app_name"这种格式,否则会出错
2.设置好属性文件后,在使用的布局中写相关配置:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:personattr="http://schemas.android.com/apk/res/com.example.declare_styleable"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <com.example.declare_styleable.PersonView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- personattr:name="@string/person_name"
- personattr:weight ="fat"
- personattr:adult ="false"
- personattr:textSize="@dimen/text_size"/>
- </RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:personattr="http://schemas.android.com/apk/res/com.example.declare_styleable"
android:layout_width="match_parent"
android:layout_height="match_parent" > <com.example.declare_styleable.PersonView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
personattr:name="@string/person_name"
personattr:weight ="fat"
personattr:adult ="false"
personattr:textSize="@dimen/text_size"/> </RelativeLayout>
这里要先应用这个attr:
- xmlns:personattr="http://schemas.android.com/apk/res/com.example.declare_styleable"
xmlns:personattr="http://schemas.android.com/apk/res/com.example.declare_styleable"
对应结构是:
- xmlns:你自己定义的名称="http://schemas.android.com/apk/res/你程序的package包名" (我这是com.example.declare_styleable)
xmlns:你自己定义的名称="http://schemas.android.com/apk/res/你程序的package包名" (我这是com.example.declare_styleable)
包名是配置文件中 package="com.example.declare_styleable" 这样格式的
之后在布局中自定义的类中设相关属性:
你自己定义的名称:你设的属性 ="属性值";
3.最后在自定义控件的构造方法中获取你配置的属性值:
- public class PersonView extends TextView {
- public PersonView(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
- }
- public PersonView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- // TODO Auto-generated constructor stub
- }
- public PersonView(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- TypedArray tArray = context.obtainStyledAttributes(attrs,R.styleable.PersonAttr);//获取配置属性
- String name = tArray.getString(R.styleable.PersonAttr_name);<span style="font-family: Arial, Helvetica, sans-serif;">//得到属性name</span>
- int age = tArray.getInt(R.styleable.PersonAttr_age, 15);
- Boolean adult = tArray.getBoolean(R.styleable.PersonAttr_adult, false);
- String str_adult = getAdultStatus(adult);
- int weight = tArray.getInt(R.styleable.PersonAttr_weight, 1);// 默认是中等身材,属性为:1
- String str_weight = getWeightStatus(weight);//获得肥胖属性
- float textSize = tArray.getDimension(R.styleable.PersonAttr_textSize,R.dimen.default_text_size);// 如果你设置为DP等单位,会做像素转换
- tArray.recycle();//回收资源
- // setTextSize(textSize);//设置字体大小
- setText("姓名:" + name + "\n" + "年龄:" + age + "\n" + "是否成年:" + str_adult
- + "\n" + "体形:" + str_weight);//给自定义的控件赋值
- }
- /** 根据传入的值判断是否成年 */
- public String getAdultStatus(Boolean adult ){
- String str_adult = "未成年";
- if (adult) {
- str_adult = "成年";
- }
- return str_adult;
- }
- /** 根据传入的值判断肥胖状态 */
- public String getWeightStatus(int weight){
- String str_weight = "中等";
- switch (weight) {
- case 0:
- str_weight = "瘦";
- break;
- case 1:
- str_weight = "中等";
- break;
- case 2:
- str_weight = "肥胖";
- break;
- default:
- break;
- }
- return str_weight;
- }
- }
public class PersonView extends TextView {
public PersonView(Context context) {
super(context);
// TODO Auto-generated constructor stub
} public PersonView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
} public PersonView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
TypedArray tArray = context.obtainStyledAttributes(attrs,R.styleable.PersonAttr);//获取配置属性
String name = tArray.getString(R.styleable.PersonAttr_name);<span style="font-family: Arial, Helvetica, sans-serif;">//得到属性name</span>
int age = tArray.getInt(R.styleable.PersonAttr_age, 15);
Boolean adult = tArray.getBoolean(R.styleable.PersonAttr_adult, false);
String str_adult = getAdultStatus(adult);
int weight = tArray.getInt(R.styleable.PersonAttr_weight, 1);// 默认是中等身材,属性为:1
String str_weight = getWeightStatus(weight);//获得肥胖属性
float textSize = tArray.getDimension(R.styleable.PersonAttr_textSize,R.dimen.default_text_size);// 如果你设置为DP等单位,会做像素转换
tArray.recycle();//回收资源
// setTextSize(textSize);//设置字体大小
setText("姓名:" + name + "\n" + "年龄:" + age + "\n" + "是否成年:" + str_adult
+ "\n" + "体形:" + str_weight);//给自定义的控件赋值
} /** 根据传入的值判断是否成年 */
public String getAdultStatus(Boolean adult ){
String str_adult = "未成年";
if (adult) {
str_adult = "成年";
}
return str_adult;
} /** 根据传入的值判断肥胖状态 */
public String getWeightStatus(int weight){
String str_weight = "中等";
switch (weight) {
case 0:
str_weight = "瘦";
break;
case 1:
str_weight = "中等";
break;
case 2:
str_weight = "肥胖";
break;
default:
break;
}
return str_weight;
}
}
运行后就是:
这样,以后我们就可以根据这个方法,去自定义控件并自定义配置属性了,大大提高了自定义布局的使用效率。
对应的源码下载地址:下载地址
android 自定义控件 使用declare-styleable进行配置属性(源码角度)的更多相关文章
- 【转】android 自定义控件 使用declare-styleable进行配置属性(源码角度)
原文网址:http://blog.csdn.net/vipzjyno1/article/details/23696537 最近在模仿今日头条,发现它的很多属性都是通过自定义控件并设定相关的配置属性进行 ...
- Android -- 带你从源码角度领悟Dagger2入门到放弃
1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...
- Android -- 带你从源码角度领悟Dagger2入门到放弃(一)
1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...
- 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING
<Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th 2014 Email:skyseraph00@163.com 更多精彩请直接 ...
- Android -- 带你从源码角度领悟Dagger2入门到放弃(二)
1,接着我们上一篇继续介绍,在上一篇我们介绍了简单的@Inject和@Component的结合使用,现在我们继续以老师和学生的例子,我们知道学生上课的时候都会有书籍来辅助听课,先来看看我们之前的Stu ...
- Android布局性能优化—从源码角度看ViewStub延迟加载技术
在项目中,难免会遇到这种需求,在程序运行时需要动态根据条件来决定显示哪个View或某个布局,最通常的想法就是把需要动态显示的View都先写在布局中,然后把它们的可见性设为View.GONE,最后在代码 ...
- 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...
- Android多线程之(一)View.post()源码分析——在子线程中更新UI
提起View.post(),相信不少童鞋一点都不陌生,它用得最多的有两个功能,使用简便而且实用: 1)在子线程中更新UI.从子线程中切换到主线程更新UI,不需要额外new一个Handler实例来实现. ...
- 【陪你系列】5 千字长文+ 30 张图解 | 陪你手撕 STL 空间配置器源码
大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub https://github.com/rongweihe/MoreT ...
随机推荐
- gridControl控件动态绑定列
DataTable dt = =Query.GetCustome=(ref customColumnCount); //绑定列 gridView.Columns.Add(}); gridView.Co ...
- 26Mybatis_一级缓存及其测试
这篇文章讲解一级缓存: 先介绍一级缓存的原理:
- UWP 解压 GZIP
准备工作: 通过 NUGET 安装 Microsoft.Bcl.Compression ; 使用命名空间 using System.IO.Compression ; public static asy ...
- 不支持一个 STA 线程上针对多个句柄的 WaitAll
[csharp] view plaincopy using System; using System.Collections.Generic; using System.Windows.Forms; ...
- vim自动添加注释
我想了下,要做好一件事, 1,首先喜欢它最才有动机去了解它 2,道听途说about那东西的,会去了解并去玩转 3,兴趣需要培养 一 添加vim头部信息. 系统:C67 追加以下代码到 /etc/vim ...
- Caffe学习系列(15):计算图片数据的均值
图片减去均值后,再进行训练和测试,会提高速度和精度.因此,一般在各种模型中都会有这个操作. 那么这个均值怎么来的呢,实际上就是计算所有训练样本的平均值,计算出来后,保存为一个均值文件,在以后的测试中, ...
- Mininet的安装与卸载
1.Mininet的卸载比较简单,只需要执行以下命令: sudo rm -rf /usr/local/bin/mn /usr/local/bin/mnexec /usr/local/lib/pytho ...
- 如何使用Iveely的数据存储引擎 Iveely Database
Iveely 数据存储引擎是为Iveely 搜索引擎提供数据存储的机制. 适用于:频繁数据插入.数据读取.数据更改或者删除数据不适合Iveely Database,存储结构是按照搜索引擎数据存储要求( ...
- Ajax在调用含有SoapHeader的webservice方法
· [WebService(Namespace = "http://tempuri.org/")] · [WebServiceBinding ...
- js判断页面出现滚动条
当可视区域小于页面的实际高度时,判定为出现滚动条 当我们在获取页面的offsetHeight高度时是包括了浏览器的边框的,浏览器的边框是2个像素, if (document.documentEleme ...