Android中Attributes、defStyleAttr、defStyleRes详解

系统自带的View可以在xml中配置属性,对于自定义View同样可以在xml中配置属性,为了使自定义的View的属性可以在xml中配置,需要以下4个步骤:

1、通过<declare-styleable>为自定义View添加属性

2、在xml中为相应的属性声明属性值

3、在运行时(一般为构造函数)获取属性值

4、将获取到的属性值应用到自定义View

一般自定义View有一个构造方法:

public class MView extends View{
    public MView(Context context) ;
    public MView(Context context, @Nullable AttributeSet attrs);
    public MView(Context context, @Nullable AttributeSet attrs, int defStyleAttr);
    public MView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) ;
}

第1个构造方法:只有一个context参数,一般用于代码中new出一个控件,它不带任何属性参数。

第2个构造方法:加载你在layout.xml文件中配置控件时调用,它有相对应的属性,例如:layout_width、background等

第3个构造方法:在第2个构造方法的基础上,额外添加一个属性,这个属性指向一个默认style

第4个构造方法:在第3个构造方法的基础上,额外添加一个style。注意:如果defStyleAttr有效(defStyleAttr不为0或者有定义defStyleAttr),则defStyleRes无效;如果defStyleAttr无效,则defStyleRes有效。defStyleAttr的优先级比defStyleRes高。

属性优先级(1>2>3>4):

1、直接在layout.xml文件中添加的属性

2、在style中添加的属性

3、defStyleAttr或defStyleRes(二者不会同时有效)

4、theme中添加的属性

自定义属性

通过<declare-styleable>元素声明自定义View需要的属性即可,下面是一个例子,文件是res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="gui">
        <attr name="attr1" format="string"></attr>
        <attr name="attr2" format="string"></attr>
        <attr name="attr3" format="string"></attr>
        <attr name="attr4" format="string"></attr>
        <attr name="attr5" format="string"></attr>
        <attr name="attr6" format="string"></attr>
        <attr name="attr7" format="reference"></attr>
    </declare-styleable>
    <attr name="attr11" format="reference"></attr>
</resources>

上述attrs.xml文件中,声明了属性集合gui和属性attr11。系统会在R.attr(R文件路径:app\build\generated\not_namespaced_r_class_sources\debug\r\包名\R.java)中生成相应的属性(R文件是在Build时候自动)

public static final class attr {
        ......
    public static final int attr1=0x7f03002b;
    public static final int attr11=0x7f03002c;
    public static final int attr2=0x7f03002d;
    public static final int attr3=0x7f03002e;
    public static final int attr4=0x7f03002f;
    public static final int attr5=0x7f030030;
    public static final int attr6=0x7f030031;
    public static final int attr7=0x7f030032;
        ......

}

不同的是,如果声明在declare-styleable中,系统还会为我们在R.styleable中生成相关的属性

public static final class styleable {
            ......
    public static final int[] gui={
      0x7f03002b, 0x7f03002d, 0x7f03002e, 0x7f03002f, 
      0x7f030030, 0x7f030031, 0x7f030032
    };
    public static final int gui_attr1=0;
    public static final int gui_attr2=1;
    public static final int gui_attr3=2;
    public static final int gui_attr4=3;
    public static final int gui_attr5=4;
    public static final int gui_attr6=5;
    public static final int gui_attr7=6;
            ......
}

如上所述,R.styable.gui是一个int[],里面元素的值正好和R.attr里的属性值一样。gui_attrX表示的是attrX在R.styleable.gui里面的索引。

在xml中添加相应的属性和属性值

在xml中添加属性和属性值的几种方式:

1、直接在layout文件中添加

2、设置style并在style中添加

3、Application和Activity可以指定theme,可以在theme中添加

直接在layout中添加

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <com.gui.gui.custom.view.component.TestView1
        android:id="@+id/testView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:attr1="attr1:layout.xml中申明"
        style="@style/XmlStyle"  />
    
</androidx.constraintlayout.widget.ConstraintLayout>

在style中添加

<style name="XmlStyle">
    <item name="attr1">attr1:在style中申明</item>
    <item name="attr2">attr2:在style中申明</item>
</style>

在theme中添加

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="attr1">attr1:在Theme中申明</item>
        <item name="attr2">attr2:在Theme中申明</item>
        <item name="attr3">attr3:在Theme中申明</item>
        <item name="attr4">attr4:在Theme中申明</item>
        <item name="attr5">attr5:在Theme中申明</item>
        <item name="attr11">@style/ThemeStyle</item>
    </style>

    <style name="ThemeStyle">
        <item name="attr1">attr1:在Theme Style中申明</item>
        <item name="attr2">attr2:在Theme Style中申明</item>
        <item name="attr3">attr3:在Theme Style中申明</item>
        <item name="attr4">attr4:在Theme Style中申明</item>
    </style>

在上述xml文件中,我们在AppTheme中添加了attr3和attr11,attr11是一个reference,指向ThemeStyle,在ThemeStyle中,我们添加了attr4属性。在theme中设置属性有两种方式:1、直接在theme中添加一个属性(例如attr4),2、定义一个reference类型属性并指向另外一个style。这两种方式是有区别的,它们的属性优先级不一样。

代码中获取属性

package com.gui.gui.custom.view.component;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.gui.gui.custom.view.R;

import androidx.annotation.Nullable;

public class TestView1 extends View {
    public TestView1(Context context) {
        this(context, null);
    }

    public TestView1(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.attr.attr11);
    }

    public TestView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, R.style.DefStyleRes);
    }

    public TestView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.gui, defStyleAttr, defStyleRes);
        log("TypedArray length:" + ta.length());
        for (int i = 0; i < ta.length(); i++) {
            int attrIndex = ta.getIndex(i);
            switch (attrIndex) {
                case R.styleable.gui_attr1:
                    log(ta.getString(attrIndex));
                    break;
                case R.styleable.gui_attr2:
                    log(ta.getString(attrIndex));
                    break;
                case R.styleable.gui_attr3:
                    log(ta.getString(attrIndex));
                    break;
                case R.styleable.gui_attr4:
                    log(ta.getString(attrIndex));
                    break;
                case R.styleable.gui_attr5:
                    log(ta.getString(attrIndex));
                    break;
                case R.styleable.gui_attr6:
                    log(ta.getString(attrIndex));
                    break;
                case R.styleable.gui_attr7:
                    log(ta.getString(attrIndex));
                    break;
                default:
                    break;
            }
        }
        ta.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    private void log(String msg) {
        Log.v(getClass().getSimpleName(), "" + msg);
    }
}

context.obtainStyledAttributes方法接受四个参数,其中Attributes、defAttr、defStyle都属于告诉程序从哪取属性,第2个参数

R.styleable.gui表示取哪些属性参数。

运行结果:

2020-01-22 15:03:22.133 14297-14297/com.gui.gui.custom.view V/TestView1: TypedArray length:7
2020-01-22 15:03:22.133 14297-14297/com.gui.gui.custom.view V/TestView1: attr1:layout.xml中申明
2020-01-22 15:03:22.133 14297-14297/com.gui.gui.custom.view V/TestView1: attr2:在style中申明
2020-01-22 15:03:22.134 14297-14297/com.gui.gui.custom.view V/TestView1: attr3:在Theme Style中申明
2020-01-22 15:03:22.134 14297-14297/com.gui.gui.custom.view V/TestView1: attr4:在Theme Style中申明
2020-01-22 15:03:22.135 14297-14297/com.gui.gui.custom.view V/TestView1: attr5:在Theme中申明

现在我们对第3个构造方法加以修改,是defStyleAttr无效

    public TestView1(Context context, @Nullable AttributeSet attrs) {
        //this(context, attrs, R.attr.attr11);
        // 改成如下参数
        this(context, attrs, 0);
    }

运行结果如下:

2020-01-22 15:08:04.188 14486-14486/com.gui.gui.custom.view V/TestView1: TypedArray length:7
2020-01-22 15:08:04.188 14486-14486/com.gui.gui.custom.view V/TestView1: attr1:layout.xml中申明
2020-01-22 15:08:04.188 14486-14486/com.gui.gui.custom.view V/TestView1: attr2:在style中申明
2020-01-22 15:08:04.189 14486-14486/com.gui.gui.custom.view V/TestView1: attr3:在def style res中申明
2020-01-22 15:08:04.189 14486-14486/com.gui.gui.custom.view V/TestView1: attr4:在def style res中申明
2020-01-22 15:08:04.190 14486-14486/com.gui.gui.custom.view V/TestView1: attr5:在Theme中申明
 
发布了81 篇原创文章 · 获赞 4 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/GracefulGuigui/article/details/104069265