美文网首页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