Android:自定义控件你应该知道的这些事_TypedArray

      在下水平不高,不喜勿喷,有错的地方请积极提出,谢谢       

Android:自定义控件你应该知道的这些事_TypedArray
Android:自定义控件你应该知道的这些事_事件分发机制

如果想要获取Android的资源文件,我们会通过context.getresource.getXXX得到,那我们今天主要记录的是利用TypeArray获取自定义属性,比如android:layout_width="match_parent"这些,其实已经是android本身已经定义好的属性,那我们应该怎么样去创建自定义属性,又怎么样去使用自定属性呢?

1.创建自定义属性

首选创建values\attrs.xml,在attrs.xml中声明自定义属性

<declare-styleable name="MyFirstCustomerView">
    <attr name="text" format="string" />
    <attr name="textColor" format="color"/>
    <attr name="textSize" format="dimension"/>
</declare-styleable>
  • 自定义string类型,属性名为text
  • 自定义color类型,属性名为textColor
  • 自定义dimension类型,属性名为textSize
    简单提一嘴:declare-styleable这个标签的作用其实就是可以为我们完成很多常量(int[]数组,下标常量)等的编写,简化我们的开发工作

既然是简单化,如果不使用declare-styleable标签来简单化,我们该怎么做?
首先自定义属性values\attrs.xml,如下

   <resources>
     <attr name="android:text" />
     <attr name="text" format="string" />
     <attr name="textColor" format="color"/>
     <attr name="textSize" format="dimension"/>
   </resources>

布局:

  <com.ffcs.z.test.view.CustomView
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:text="aaaa"
    app:text="@string/text"
    app:textColor="@color/colorPrimaryDark"
    app:textSize="18sp" />

获取自定义属性方法
private static final int[] mAttr = { android.R.attr.text,R.attr.text,R.attr.textColor,R.attr.textSize};//想要获取的attr的id

   TypedArray a = context.obtainStyledAttributes(attrs, mAttr);
    String android_text = a.getString(0);
    String text = a.getString(a.getIndex(1));
    int color=a.getColor(a.getIndex(2),textColor);
    int textSize=a.getDimensionPixelSize(a.getIndex(3),20);
    //输出 text = Hello world! , textAttr = 520
    Log.e(TAG, "text = " + text + " , textAttr = " + text);
    Log.i("TypedArray=>", "attrName_android_text:" + android_text +"\r\nattrName_text:" + text + "\r\nattrName_color:" + color + "\r\nattrName_textSize:" + textSize);
    a.recycle();

Log输出:

              TypedArray=>: attrName_android_text:aaaa
                            attrName_text:这是一个自定以空间
                            attrName_color:-13615201
                            attrName_textSize:54

format还有如下类型

format 介绍
reference 表示引用,参考某一资源ID
string 表示字符串
color 表示颜色值
dimension 表示尺寸值
boolean 表示布尔值
integer 表示整型值
float 表示浮点值
fraction 表示百分数
enum 表示枚举值
flag 表示位运算

2.布局文件中使用自定义属性

首先需要在根布局中申明 xmlns:app="http://schemas.android.com/apk/res-auto"

<com.ffcs.z.test.view.CustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:text="这是自定义属性"
    app:textColor="@android:color/black"
    app:textSize="18sp"/>

CustomView是自定义控件,引用了app:text、app:textColor、 app:textSize="18sp"三个自定义属性

3.自定义控件CustomView

public class CustomView extends View {

public Paint paint;
private String text = "";//文本内容
private int textColor = 0xDD333333;  //字体颜色
private float textSize = 20;//字体大小设置

public CustomView(Context context) {
    this(context, null);
}

public CustomView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(attrs);
}

private void init(AttributeSet attrs) {
    TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CustomerView);//获取TypedArray
    textColor = a.getColor(R.styleable.CustomerView_textColor, textColor);//获取布局中设置的自定以颜色
    textSize = a.getDimension(R.styleable.CustomerView_textSize, textSize);//获取布局中设置的自定义字体大小
    text = a.getString(R.styleable.CustomerView_text);//获取布局中设置的自定义文本
    paint = new Paint();//初始化 画笔
    paint.setTextSize(textSize);//画笔字体大小设置
    paint.setColor(textColor);//画笔的颜色
    paint.setStyle(Paint.Style.FILL);//画笔风格
    a.recycle();//切记:在使用TypedArray后需要回收
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawText(text, 100, 100, paint);
}}

-TypedArray用完一定要回收


自定义控件.png

好像丑了点,但是凑合看一下吧

了解自定义控件中构造函数的参数

Parameters 参数解释
Context 当前上下文
AttributeSet 为xml里一个节点下面的属性的集合,这个类一般都是系统在生成有xml配置的组件时生成,可以理解为当前自定义控件下的所有属性集合;提供TypedArray检索的范围
defStyleAttr 在当前包含了一个引用到为TypedArray提供默认值的样式资源的theme中的一种属性。可以为0,但是为0的时候就不会再去寻找默认的;提供TypedArray检索的范围(注:这里的默认也就是defStyleRes)

AttributeSet

讲个栗子,获取属性_字体的大小需要通过AttributeSet :

    int textSize = attrs.getAttributeResourceValue(null, "textSize", 0);  
    if (textSize != 0) {  
        mEditText.setTextSize(textSize);  
    }  

那么问题就来了,既然AttributeSet 和TypedArray都能获取到xml文件下的属性值,
直接用AttributeSet去获取xml文件下的自定义属性,为啥还要费力去初始TypedArray
去获取呢?接着看

<com.ffcs.z.test.view.CustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:text="@string/text"
    app:textColor="@color/colorPrimaryDark"
    app:textSize="18sp" />

分别输出AttributeSet和TypedArray获取到的属性值

    int count = attrs.getAttributeCount();
    for (int i = 0; i < count; i++) {
        String attrName = attrs.getAttributeName(i);
        String attrVal = attrs.getAttributeValue(i);
        Log.i("attrs=>", "attrName = " + attrName + " , attrVal = " + attrVal);
    }

  TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CustomerView);//获取TypedArray
    textColor = a.getColor(R.styleable.CustomerView_textColor, textColor);//获取布局中设置的自定以颜色
    textSize = a.getDimension(R.styleable.CustomerView_textSize, textSize);//获取布局中设置的自定义字体大小
    text = a.getString(R.styleable.CustomerView_text);//获取布局中设置的自定义文本
    Log.i("TypedArray=>", "attrName_text:" + text + "\r\nattrName_textColor:" + textColor + "\r\nattrName_textSize:" + textSize);

输出Log

attrs=>: attrName = layout_width , attrVal = 200.0dip
attrs=>: attrName = layout_height , attrVal = 200.0dip
attrs=>: attrName = text , attrVal = @2131099685
attrs=>: attrName = textColor , attrVal = @2131427350
attrs=>: attrName = textSize , attrVal = 18.0sp
TypedArray=>: attrName_text:这是一个自定以空间
attrName_textColor:-13615201
attrName_textSize:54.0

这边我们看一下 text 用AttributeSet输出的是什么鬼,肯定用不了,那我们看一下TypedArray获取到的数值,松了一口气,瞬间明白了AttributeSet和TypedArray获取属性的区别:如果布局中属性的值是引用类型(比如:@string/text),使用AttributeSet去获得最终的字符串,那么需要第一步拿到id,第二步再去解析id,而TypedArray正是帮我们简化了这个过程。

那么有人就要问了,我们如果去获得android已经定义好了的属性,该咋整呢?举个栗子,比如上面我们都用到text,app:text和android:text,功能都一样,但是我更想要使用android:text,那么自定义组件中我改怎么去获取呢?

    <declare-styleable name="test">
        <attr name="android:text" />
    </declare-styleable>

这里我们是使用已经定义好的属性,不需要去添加format属性,这是自定义和声明的区别

TypedArray创建

TypedArray a =getResources().obtainAttributes();
-是 Resources 的函数

TypedArray a = context.obtainStyledAttributes();
-Resources.Theme 的函数
-此方法有四个重载方法
obtainStyledAttributes(int[] attrs)
obtainStyledAttributes(int resid, int[] attrs)
obtainStyledAttributes(AttributeSet set, int[] attrs)
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)

简单说,其中的参数为检索的范围 优先级xml > style > defStyleAttr > defStyleRes > theme其中3/4构造函数为最常用(PS:此处待补充)

获取自定属性正确姿势

format 介绍
string typedArray.getString(R.styleable.xxx);
color typedArray.getColor(R.styleable.xxx, 默认值);
boolean typedArray.getBoolean(R.styleable.xxx, 默认值);
integer typedArray.getInteger(R.styleable.xxx, 默认值)
float typedArray.getFloat(R.styleable.xxx, 默认值)
fraction typedArray.getFraction(R.styleable.xxx, 分子, 分母,默认值)
enum typedArray.getInt(R.styleable.xxx, 默认值);
flag typedArray.getInt(R.styleable.xxx,默认值);
dimension sp:typedArray.getDimension(R.styleable.xxx, 20);dp:typedArray.getDimensionPixelOffset(typedArray.getIndex(R.styleable.xxx), 20); 或:private float radius = 3; radius=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,radius,getResources().getDisplayMetrics());radius = typedArray.getDimension(R.styleable.xxx, normalRadius);

总结

  • declare-styleable标签可以为我们完成很多常量(int[]数组,下标常量)等的编写,简化我们的开发工作,可以不声明,但是需要在自定义控件中,声明引用自定义属性数组
  • TypedArray 可有obtainAttributes()、obtainStyledAttributes()方法创建,常用obtainStyledAttributes(int resid, int[] attrs)构造方法
  • TypedArray和AttributeSet区别在于,布局中引用参数为id时的不同(@string/text),所获取的值不同
  • format如果为dimension时,注意:sp和dp需要转化

此文部分理解于:
【张鸿洋的博客】Android 深入理解Android中的自定义属性

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容