美文网首页Android开发
Android:自定义控件你应该知道的这些事_TypedArra

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

作者: Z_Liqiang | 来源:发表于2018-01-05 09:17 被阅读86次
      在下水平不高,不喜勿喷,有错的地方请积极提出,谢谢       

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中的自定义属性

相关文章

网友评论

    本文标题:Android:自定义控件你应该知道的这些事_TypedArra

    本文链接:https://www.haomeiwen.com/subject/ahjjnxtx.html