1、为什么要自定义属性

要使用属性,首先这个属性应该存在,所以如果我们要使用自己的属性,必须要先把他定义出来才能使用。但我们平时在写布局文件的时候好像没有自己定义属性,但我们照样可以用很多属性,这是为什么?我想大家应该都知道:系统定义好的属性我们就可以拿来用呗,但是你们知道系统定义了哪些属性吗?哪些属性是我们自定义控件可以直接使用的,哪些不能使用?什么样的属性我们能使用?这些问题我想大家不一定都弄得清除,下面我们去一一解开这些谜团。   系统定义的所有属性我们可以在\sdk\platforms\Android-xx\data\res\values目录下找到attrs.xml这个文件,这就是系统自带的所有属性,打开看看一些比较熟悉的:

<declare-styleable name="View"><attr name="id" format="reference" /> <attr name="background" format="reference|color" /> <attr name="padding" format="dimension" /> ... <attr name="focusable" format="boolean" /> ... </declare-styleable> <declare-styleable name="TextView"> <attr name="text" format="string" localization="suggested" /> <attr name="hint" format="string" /> <attr name="textColor" /> <attr name="textColorHighlight" /> <attr name="textColorHint" /> ... </declare-styleable> <declare-styleable name="ViewGroup_Layout"> <attr name="layout_width" format="dimension"> <enum name="fill_parent" value="-1" /> <enum name="match_parent" value="-1" /> <enum name="wrap_content" value="-2" /> </attr> <attr name="layout_height" format="dimension"> <enum name="fill_parent" value="-1" /> <enum name="match_parent" value="-1" /> <enum name="wrap_content" value="-2" /> </attr> </declare-styleable> <declare-styleable name="LinearLayout_Layout"> <attr name="layout_width" /> <attr name="layout_height" /> <attr name="layout_weight" format="float" /> <attr name="layout_gravity" /> </declare-styleable> <declare-styleable name="RelativeLayout_Layout"> <attr name="layout_centerInParent" format="boolean" /> <attr name="layout_centerHorizontal" format="boolean" /> <attr name="layout_centerVertical" format="boolean" /> ... </declare-styleable> 

看看上面attrs.xml文件中的属性,发现他们都是有规律的分组的形式组织的。以declare-styleable 为一个组合,后面有一个name属性,属性的值为View 、TextView 等等,有没有想到什么?没错,属性值为View的那一组就是为View定义的属性,属性值为TextView的就是为TextView定义的属性…。

因为所有的控件都是View的子类,所以为View定义的属性所有的控件都能使用,这就是为什么我们的自定义控件没有定义属性就能使用一些系统属性。

但是并不是每个控件都能使用所有属性,比如TextView是View的子类,所以为View定义的所有属性它都能使用,但是子类肯定有自己特有的属性,得单独为它扩展一些属性,而单独扩展的这些属性只有它自己能有,View是不能使用的,比如View中不能使用android:text=“”。又比如,LinearLayout中能使用layout_weight属性,而RelativeLayout却不能使用,因为layout_weight是为LinearLayout的LayoutParams定义的。

综上所述,自定义控件如果不自定义属性,就只能使用VIew的属性,但为了给我们的控件扩展一些属性,我们就必须自己去定义。

2、怎样自定义属性

翻阅系统的属性文件,你会发现,有的这中形式,有的是;这两种的区别就是attr标签后面带不带format属性,如果带format的就是在定义属性,如果不带format的就是在使用已有的属性,name的值就是属性的名字,format是限定当前定义的属性能接受什么值。

打个比方,比如系统已经定义了android:text属性,我们的自定义控件也需要一个文本的属性,可以有两种方式:

第一种:我们并不知道系统定义了此名称的属性,我们自己定义一个名为text或者mText的属性(属性名称可以随便起的)

<resources><declare-styleable name="MyTextView"> <attr name=“text" format="string" /> </declare-styleable> </resources> 

第二种:我们知道系统已经定义过名称为text的属性,我们不用自己定义,只需要在自定义属性中申明,我要使用这个text属性
(注意加上android命名空间,这样才知道使用的是系统的text属性)

<resources><declare-styleable name="MyTextView"> <attr name=“android:text"/> </declare-styleable> </resources> 

3、属性值的类型format

format支持的类型一共有11种:
(1). reference:参考某一资源ID

属性定义:

<declare-styleable name = "名称"><attr name = "background" format = "reference" /> </declare-styleable> 

属性使用:

<ImageView android:background = "@drawable/图片ID"/>
(2). color:颜色值

属性定义:

<attr name = "textColor" format = "color" /> 

属性使用:

<TextView android:textColor = "#00FF00" />
(3). boolean:布尔值

属性定义:

<attr name = "focusable" format = "boolean" /> 

属性使用:

<Button android:focusable = "true"/>
(4). dimension:尺寸值

属性定义:

<attr name = "layout_width" format = "dimension" /> 

属性使用:

<Button android:layout_width = "42dip"/>
(5). float:浮点值

属性定义:

<attr name = "fromAlpha" format = "float" /> 

属性使用:

<alpha android:fromAlpha = "1.0"/>
(6). integer:整型值

属性定义:

<attr name = "framesCount" format="integer" /> 

属性使用:

<animated-rotate android:framesCount = "12"/>
(7). string:字符串

属性定义:

<attr name = "text" format = "string" /> 

属性使用:

<TextView android:text = "我是文本"/>
(8). fraction:百分数

属性定义:

<attr name = "pivotX" format = "fraction" /> 

属性使用:

<rotate android:pivotX = "200%"/>
(9). enum:枚举值

属性定义:

<declare-styleable name="名称"><attr name="orientation"> <enum name="horizontal" value="0" /> <enum name="vertical" value="1" /> </attr> </declare-styleable> 

属性使用:

<LinearLayout  android:orientation = "vertical">
</LinearLayout> 

注意:枚举类型的属性在使用的过程中只能同时使用其中一个,不能 android:orientation = “horizontal|vertical"

(10). flag:位或运算

属性定义:

<declare-styleable name="名称"><attr name="gravity"> <flag name="top" value="0x30" /> <flag name="bottom" value="0x50" /> <flag name="left" value="0x03" /> <flag name="right" value="0x05" /> <flag name="center_vertical" value="0x10" /> ... </attr> </declare-styleable> 

属性使用:

<TextView android:gravity="bottom|left"/>

注意:位运算类型的属性在使用的过程中可以使用多个值

(11). 混合类型:属性定义时可以指定多种类型值

属性定义:

<declare-styleable name = "名称"><attr name = "background" format = "reference|color" /> </declare-styleable> 

属性使用:

<ImageView
android:background = "@drawable/图片ID" />
或者:
<ImageView android:background = "#00FF00" /> 

通过上面的学习我们已经知道怎么定义各种类型的属性,以及怎么使用它们,但是我们写好布局文件之后,要在控件中使用这些属性还需要将它解析出来。

4、类中获取属性值

按照上面学习的知识,我们先定义一些属性,并写好布局文件。
先在res\values目录下创建attrs.xml,定义自己的属性:

<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyTextView"> <!--声明MyTextView需要使用系统定义过的text属性,注意前面需要加上android命名--> <attr name="android:text" /> <attr name="mTextColor" format="color" /> <attr name="mTextSize" format="dimension" /> </declare-styleable> </resources> 

在布局文件中,使用属性(注意引入我们应用程序的命名空间,这样在能找到我们包中的attrs):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:openxu="http://schemas.android.com/apk/res-auto"android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <com.dengxiao.customviewone.MyTextView android:layout_width="200dip" android:layout_height="100dip" openxu:mTextSize="25sp" android:text="我是文字" openxu:mTextColor ="#0000ff" android:background="#ff0000"/> </LinearLayout> 

在构造方法中获取属性值:

public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyTextView);String text = ta.getString(R.styleable.MyTextView_android_text);int mTextColor = ta.getColor(R.styleable.MyTextView_mTextColor, Color.BLACK);int mTextSize = ta.getDimensionPixelSize(R.styleable.MyTextView_mTextSize, 100);ta.recycle();  //注意回收Log.d("DX", “text属性值:"+mText); Log.d("DX", "mTextColor属性值:"+mTextColor); Log.d("DX", "mTextSize属性值:"+mTextSize); } 

log输出:

DX: mText属性值:我是文字
DX: mTextColor属性值:-16776961 DX: mTextSize属性值:75 

到此为止,是不是发现自定义属性是如此简单?

属性的定义我们应该学的差不多了,但有没有发现构造方法中获取属性值的时候有两个比较陌生的类AttributeSet 和TypedArray,这两个类是怎么把属性值从布局文件中解析出来的?

5、Attributeset和TypedArray以及declare-styleable

Attributeset看名字就知道是一个属性的集合,实际上,它内部就是一个XML解析器,帮我们将布局文件中该控件的所有属性解析出来,并以key-value的兼职对形式维护起来。其实我们完全可以只用他通过下面的代码来获取我们的属性就行。

public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); int count = attrs.getAttributeCount(); for (int i = 0; i < count; i++) { String attrName = attrs.getAttributeName(i); String attrVal = attrs.getAttributeValue(i); Log.e("openxu", "attrName = " + attrName + " , attrVal = " + attrVal); } } 

log输出:

DX: attrName = background , attrVal = @2131427347
DX: attrName = layout_width , attrVal = 200.0dip
DX: attrName = layout_height , attrVal = 100.0dip DX: attrName = text , attrVal = 我是文字 DX: attrName = mTextSize , attrVal = 25sp DX: attrName = mTextColor , attrVal = #0000ff 

发现通过Attributeset获取属性的值时,它将我们布局文件中的值原原本本的获取出来的,比如宽度200.0dip,其实这并不是我们想要的,如果我们接下来要使用宽度值,我们还需要将dip去掉,然后转换成整形,这多麻烦。其实这都不算什么,更恶心的是,backgroud我应用了一个color资源ID,它直接给我拿到了这个ID值,前面还加了个@,接下来我要自己获取资源,并通过这个ID值获取到真正的颜色。

使用TypedArray获取属性值:
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyTextView); String mText = ta.getString(R.styleable.MyTextView_android_text); int mTextColor = ta.getColor(R.styleable.MyTextView_mTextColor, Color.BLACK); int mTextSize = ta.getDimensionPixelSize(R.styleable.MyTextView_mTextSize, 100); float width = ta.getDimension(R.styleable.MyTextView_android_layout_width, 0.0f); float hight = ta.getDimension(R.styleable.MyTextView_android_layout_height,0.0f); int backgroud = ta.getColor(R.styleable.MyTextView_android_background, Color.BLACK); ta.recycle(); //注意回收 Log.d("DX", "width:"+width); Log.d("DX", "hight:"+hight); Log.d("DX", "backgroud:"+backgroud); Log.d("DX", "mText:"+mText); Log.d("DX", "mTextColor:"+mTextColor); Log.d("DX", "mTextSize:"+mTextSize);ext, 0, mText.length(), mBound); 

log输出:

DX: width:600.0
DX: hight:300.0 DX: backgroud:-12627531 DX: mText:我是文字 DX: mTextColor:-16777216 DX: mTextSize:100 

看看多么舒服的结果,我们得到了想要的宽高(float型),背景颜色(color的十进制)等,TypedArray提供了一系列获取不同类型属性的方法,这样就可以直接得到我们想要的数据类型,而不用像Attributeset获取属性后还要一个个处理才能得到具体的数据,实际上TypedArray是为我们获取属性值提供了方便,注意一点,TypedArray使用完毕后记得调用 ta.recycle();回收 。

作者:赫丹
链接:https://www.jianshu.com/p/05ccc62bebbf
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转载于:https://www.cnblogs.com/Im-Victor/p/8870461.html

Android 自定义View二(深入了解自定义属性attrs.xml)相关推荐

  1. android下雨动画效果,Android 自定义View(二) 下雨效果

    Rain.gif Android 自定义View(二) 下雨效果 一 实现思路, 雨点用线段表示,通过控制线段的大小和宽度来表示不同的线段. 一个雨点下雨的过程可以表示为一条直线,一次雨点在下雨的过程 ...

  2. Android自定义View(二)

    文章目录 1.构造函数 2.onMeasure() 2.1.MeasureSpec 3.onSizeChanged() 4.onLayout() 5.onDraw() 上一篇: Android自定义V ...

  3. Android自定义View(三)自定义属性AttributeSet

    自定义View的时候通常需要提供一些自定义属性,自定义属性非常简单,只需要在res资源目录的values目录下创建一个attrs.xml的属性定义文件,然后在该文件中定义相应的属性,并在自定义View ...

  4. Android 自定义View绘制的基本开发流程 Android自定义View(二)

    1 View绘制的过程 View的测量--onMeasure() View的位置确定--onLayout() View的绘制--onDraw() 2 View的测量--onMeasure() Andr ...

  5. 精通Android自定义View(二十)自定义仿微信扫一扫效果

    1 效果 2 源码 /*** 自动上下扫描*/public class AutoScannerView extends View {private static final String TAG = ...

  6. android自定义view(二)-仿华为卡包效果

    前段时间产品经理出了一个卡列表展示效果,效果的大致样子是仿照华为门禁卡卡包效果,研究了一下大致效果出来了,但和华为比还有点差距,主要是动画不是很流畅,仅供大家参考指正,有好的优化方式也可以告诉我,大家 ...

  7. 精通Android自定义View(十二)绘制圆形进度条

    1 绘图基础简析 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制 ...

  8. 精通Android自定义View(五)自定义属性值使用详情

    1 可查看Android自定义View的基本使用 1 精通Android自定义View(一)自定义控的基本使用 2 精通Android自定义View(二)自定义属性使用详解 2 string 字符串 ...

  9. Android自定义View:ViewGroup(三)

    自定义ViewGroup本质是什么? 自定义ViewGroup本质上就干一件事--layout. layout 我们知道ViewGroup是一个组合View,它与普通的基本View(只要不是ViewG ...

最新文章

  1. 推荐一个小而美的Python代码格式化工具
  2. java 友好时间显示_java 友好的显示时间
  3. 初学者成为优秀Java程序员的8个步骤
  4. 如何用python完成评分功能呢_从文件python进行单词分析和评分
  5. 花呗下调部分年轻用户额度,倡导理性消费,网友:是嫌我穷了吗?
  6. python unittest断言_python接口自动化(二十四)--unittest断言——中(详解)
  7. 二分--1043 - Triangle Partitioning
  8. Windows系统安装jdk1.6
  9. rhadoop之mapreduce函数
  10. 计算机考研专业课408什么意思,考研408是什么意思
  11. Openstack 环境下虚拟机KVM之间的互通
  12. FireFox火狐浏览器历史版本下载地址
  13. Oracle 计算起始日期之间的工作日天数(目前只支持同一年)
  14. excel 常用技巧
  15. ML之interpret:基于titanic泰坦尼克是否获救二分类预测数据集利用interpret实现EBC模型可解释性之全局解释/局部解释案例
  16. 如何把IP-GUARD发布到公网IP来管理全国分公司的终端
  17. Javascript错误处理——try...catch
  18. 零基础如何学素描——什么是结构素描…
  19. quartus——使用vhdl语言实现层次化设计
  20. CSS学习07之字体样式

热门文章

  1. L4级自动驾驶,插上车路协同的翅膀才能飞?
  2. 【ava数据集】ava数据集下载 使用迅雷
  3. IBM X3530 M4 RAID 卡驱动下载
  4. 各位单身狗的福音:表白爱心魔改版
  5. 在使用JOOQ前,这些问题不能不清楚
  6. java.util.sortedmap_Java SortedMap lastKey()用法及代码示例
  7. 29 外观模式(Facade模式)详解
  8. 用串口(TFTP)给设备升级程序
  9. 支付宝小程 rich-text标签不显示问题解决
  10. 蓝牙时断时续很让人恼火,该如何解决(主要针对Windows 10)