View绘制体系(三)——AttributeSet与TypedArray详解
View绘制体系(三)——AttributeSet与TypedArray详解
前言
上篇博客中讲了LayoutInflater.inflate
机制,其中提到了AttributeSet
和XmlPullParser
两个接口,这里我们来详细的了解一下Android中提供的AttributeSet
接口和它与XmlPullParser
的区别,以及如何使用TypedArray
获取AttributeSet
中对应的属性。
AttributeSet
AttributeSet
是xml文件中元素属性的一个集合。其中提供了各种Api,供我们从已编译好的xml文件获取属性值,如getAttributeIntValue
,getAttributeBooleanValue
,getAttributeFloatValue
等,会返回对应类型的属性值,传入的参数一般有两种形式,如下:
getAttributeXXXValue(int index, XXX defaultValue)
:根据对应属性的索引获取对应的属性值,index取值范围在0~count-1之间,找不到返回defaultValue
getAttributeXXXValue(String namespace, String attribute, XXX defaultValue)
:根据指定命名空间的属性名获取对应的属性值,找不到返回defaultValue
AttributeSet与XmlPullParser
我们现在知道了AttributeSet也是获取xml文件中属性值用的接口,那么它和XmlPullParser有什么关联和区别呢?
我们先看下下面这张类图:
XmlPullParser和AttributeSet都能从Xml文件中获取数据,它们的相同点为:
- 它们有一些重复的方法,如
getAttributeName
,getAttributeValue
等。
区别在于:
- AttributeSet提供了额外的一系列
getAttributeXXXValue
的方法(如getAttributeIntValue),这些方法能返回对应XXX的类型值(如int值),而XmlPullParser获取属性值只能通过getAttributeValue
方法,返回值只能是String类型 - AttributeSet接口从XmlPullParser接口中只保留了必要的方法,去除了next()等方法,并且新增了一些Android独有的方法,可以说AttributeSet是Android独有的用来获取xml文件属性的一个接口
需要注意的是,在Android中,对于AttributeSet接口和XmlPullParser接口,其实现都是结合已有的编译好的xml资源,这些资源是编译时经过aapt生成的高度优化的资源,而不是通过pull方式解析原有的Xml字符串。这与我们常见的一般的XmlPullParser接口的实现机制(kXml,WbXml等)不同。
我们从类图中可以看到实现类有两个,分别是Parser
和XmlPullAttributes
,我们可以看下XmlPullAttributes
的具体实现:
class XmlPullAttributes implements AttributeSet {XmlPullParser mParser;public XmlPullAttributes(XmlPullParser parser) {mParser = parser;}public int getAttributeCount() {return mParser.getAttributeCount();}public String getAttributeNamespace (int index) {return mParser.getAttributeNamespace(index);}public String getAttributeName(int index) {return mParser.getAttributeName(index);}public String getAttributeValue(int index) {return mParser.getAttributeValue(index);}public String getAttributeValue(String namespace, String name) {return mParser.getAttributeValue(namespace, name);}public String getPositionDescription() {return mParser.getPositionDescription();}public int getAttributeNameResource(int index) {return 0;}public int getAttributeListValue(String namespace, String attribute,String[] options, int defaultValue) {return XmlUtils.convertValueToList(getAttributeValue(namespace, attribute), options, defaultValue);}//...其余AttributeSet中的接口都是类似getAttributeListValue通过XmlUtils转换类型来实现的}
可以看到XmlPullAttributes对于AttributeSet中和XmlPullParser相同的接口都是通过内部的XmlPullParser变量来实现的。
XmlPullParser还可以通过以下方式生成对应的AttributeSet:
public static AttributeSet asAttributeSet(XmlPullParser parser) {return (parser instanceof AttributeSet)? (AttributeSet) parser: new XmlPullAttributes(parser);
}
TypedArray
然而,我们很少用到AttributeSet类提供的方法来获取它的属性,常常都是通过Theme.obtainStyledAttributes方法来获取其中的属性的,方法如下:
public TypedArray obtainStyledAttributes(AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes)
获取到TypedArray之后,再去调用TypedArray的Api来处理。
为什么不直接用AttributeSet来解析属性值呢?
我们可以看下面这个xml布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="@dimen/w_50dp"android:layout_height="@dimen/w_50dp"android:orientation="vertical"/>
我们通过AttributeSet
直接去获取属性的话:
final XmlResourceParser parser = getResources().getLayout(R.layout.ll);
int type;
while ((type = parser.getEventType()) != XmlPullParser.START_TAG&& type != XmlPullParser.END_DOCUMENT) {parser.next();
}
int count = parser.getAttributeCount();
Log.d(TAG, "count: " + parser.getAttributeCount());AttributeSet attributeSet = Xml.asAttributeSet(parser);for (int i = 0; i < count; i++) {String name = attributeSet.getAttributeName(i);String value = attributeSet.getAttributeValue(i);Log.d(TAG, "attribute: " + name + " value: " + value);
}int resourceId = attributeSet.getAttributeResourceValue("http://schemas.android.com/apk/res/android", "layout_height", 0);
float dimension = getResources().getDimension(resourceId);
Log.d(TAG, "layout_height: " + dimension);
得到的结果如下:
count: 3
attribute: orientation value: 1
attribute: layout_width value: @2131034226
attribute: layout_height value: @2131034226
layout_height: 150.0 #得到的是px
可以看到如果直接使用AttributeSet
来获取属性值有以下缺点:
- 通过索引index获取元素属性颇为麻烦,而且对于属性的顺序不熟悉的人很难将将index和属性值一一对应;而通过命名空间来获取,又要必须填入android的命名空间"http://schemas.android.com/apk/res/android",编写起来都是不太方便的
- 对于"@String/hello_world"这一类通过索引资源文件获取属性值的,直接通过
getAttributeValue
获得的只是资源的id,虽然可以通过getAttributeResourceValue
获取到id后,通过Resources
类来获取对应的属性值,但是这样会有多步的操作。
我们来看看使用TypedArray是如何获取属性值的。TypedArray是一个存放属性值数组的一个容器,通常通过如下方式来获得TypedArray的:
Resources.Theme.obtainStyledAttributes(AttributeSet set,@StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes)
我们来分别看下每个参数的含义:
AttributeSet set
:表示从AttributeSet中挑选属性,可以为空int[] attrs
:表示你想挑选的属性,你想得到哪些属性,你就可以将其写到这个int数组中int defStyleAttr
:表示从defStyleAttr中挑选属性,可以为空int defStyleRes
:表示从defStyleRes中挑选属性,可以为空
这里我们先来演示下从AttributeSet
中挑选属性:
TypedArray a = obtainStyledAttributes(attributeSet,new int[] { android.R.attr.layout_width, android.R.attr.layout_height});
float width = a.getDimension(0, 0f); //第一个参数表示在int数组中的索引,第二个参数为默认值
Log.d(TAG, "typedarray layout_width: " + width);
float height = a.getDimension(1, 0f); //第一个参数表示在int数组中的索引,第二个参数为默认值
Log.d(TAG, "typedarray layout_width: " + height);
可以得到对应的值:
typedarray layout_width: 150.0
typedarray layout_width: 150.0
TypedArray提供了各种Api,如getInteger
,getString
,getDimension
等方法来获取属性值,这些方法都需要传入对应属性名在obtainStyledAttributes
中的int数组的位置索引。
对于TypedArray的分析,这里就只讲从AttributeSet中挑选属性的用法,从defStyleAttr和defStyleRes中挑选属性的用法详见[View绘制体系(四)——TypedArray与自定义属性]。
ps:对于AttributeSet与TypedArray的分析就到这里,后续将会介绍TypedArray与自定义属性的相关内容,敬请关注!
View绘制体系(三)——AttributeSet与TypedArray详解相关推荐
- android view使用方法,Android View构造方法第三参数使用方法详解
我们都知道,在Android中要使用一个View,一般会有两种方式: 在XML文件中配置: 直接在代码中new一个View的对象. 我们今天讨论的内容就是围绕着View的构造方法的. 1.实例 首先我 ...
- View 绘制体系知识梳理(7) getMeasuredWidth 和 getWidth 的区别
前言 前几天被问到了getMeasuredWidth和getWidth之间的区别,因此回来看了一下源码,又顺便复习了一遍measure/layout/draw的过程,有兴趣的同学可以看前面的几篇文章 ...
- 对tcp三次握手的详解之 理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number)
重要 !!!!!!!!! 转载自[怀揣梦想,努力前行] 对tcp三次握手的详解之 理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number) ...
- android 说话水波动画,Android实用View——水波动画效果多种实现方式详解
原标题:Android实用View--水波动画效果多种实现方式详解 这次给大家带来的是一篇关于自定义View实现水波动画效果的文章,其实在去年项目中使用过类似的动画,当时就自定义View也实现了预期的 ...
- matlab三次样条曲线的绘制(spline和csape函数详解)
matlab三次样条函数的绘制(spline和csape函数详解) 前言 1.spline函数详解 1.一维非节点边界 2.第二边界条件 3.高维无约束 4.高维第二边界 5.利用第二边界条件绘制圆 ...
- Spring Cloud Eureka 入门 (三)服务消费者详解
2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! "真正的进步 ...
- 【Tools】VMware虚拟机三种网络模式详解和操作
00. 目录 文章目录 00. 目录 01. VMware虚拟机三种网络模式 02. Bridged(桥接模式) 03. NAT(地址转换模式) 04. Host-Only(仅主机模式) 05. 参考 ...
- JavaWeb --第三章 HTTP协议详解
JavaWeb --第三章 HTTP协议详解 Http 什么是HTTP HTTP: 超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常 ...
- C语言中三个数比较大小详解——三种方法
C语言中三个数比较大小详解--三种方法 方法一:if-else法 方法二:函数法 方法三:三目运算符法 C语言中比较三个数的大小有很多方法,以下是我总结的三种方法: 首先我定义 int a = 1 ...
最新文章
- 柯南君:看大数据时代下的IT架构(5)消息队列之RabbitMQ--案例(Work Queues起航)...
- 始于TensorFlow ,终于PyTorch
- 人脸识别有风险,美国全面禁止,可为什么中国却全面推广?
- BAP存储属性的思想
- C/C++中函数参数传递
- C++ 判断类是否有某变量
- 【云服务】浅析XaaS
- “C# 未在本地计算机上注册microsoft.Jet.OLEDB.12.0”的解决方案
- linux命令、vi编辑器常用命令
- 机器人控制器编程课程-教案02-基础
- web嵌入flowplayer流媒体播放器
- 带你深入剖析TCP/IP协议、TCP协议和UDP协议、IP协议
- TS中的方法重载,函数重载,构造器重载
- ssrs报表服务器数据库配置文件,ReportingServicesService 配置文件
- 直方图都看不懂,怎么可能拍出好照片!
- 《信贷的逻辑与常识》笔记
- 单线激光雷达(Lidar)学习一:使用单线lidar进行测距
- 这所北京计算机类大学,改考408了!北京信息科技大学
- you belong with me(你属于我)
- 2021苹果cms模板集合新增苹果cms首涂模板