Details of Attributes, defStyleAttr and defStyleRes in Android

Keywords: xml Android Attribute encoding

The system's own View can be configured in xml, and the custom View can also be configured in xml. In order to enable the custom View's properties to be configured in xml, the following four steps are required:

1. Add attributes for custom View through < declare styleable >

2. Declare the attribute value for the corresponding attribute in xml

3. Get property values at run time (usually constructor)

4. Apply the obtained property value to the custom View

Generally, there is a construction method for user-defined 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) ;
}

The first construction method: there is only one context parameter, which is generally used for a new control in the code without any property parameters.

The second construction method: it is called when loading the control you configure in the layout.xml file. It has corresponding properties, such as layout ﹣ width, background, etc

Third constructor: add an additional attribute based on the second constructor, which points to a default style

Fourth constructor: add an additional style based on the third constructor. Note: if defStyleAttr is valid (defStyleAttr is not 0 or defStyleAttr is defined), defStyleRes is invalid; if defStyleAttr is invalid, defStyleRes is valid. defStyleAttr has a higher priority than defStyleRes.

Attribute priority (1 > 2 > 3 > 4):

1. Attributes added directly in the layout.xml file

2. Properties added in style

3. defStyleAttr or defstyleres (both will not be valid)

4. Properties added in theme

Custom properties

Declare the attributes required by the custom View through the < declare styleable > element. Here is an example. The file is 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>

In the above attrs.xml file, the attribute set gui and attribute attr11 are declared. The system will generate corresponding attributes in R.attr(R file path: app \ Build \ generated \ not \ namepacked \ R \ class \ sources \ debug \ R \ package name \ R.java) (r file is automatically generated when building)

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;
        ......

}

The difference is that if the declaration is in declare styleable, the system will also generate relevant properties for us in 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;
            ......
}

As mentioned above, R.styable.gui is an int [], where the value of the element is exactly the same as that of the attribute in R.attr. GUI [attrX] indicates the index of attrX in R.styleable.gui.

Add corresponding attribute and attribute value in xml

There are several ways to add attributes and attribute values to xml:

1. Add directly to the layout file

2. Set style and add in style

3. Application and Activity can specify theme, which can be added in theme

Add directly to 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 Affirming in the middle"
        style="@style/XmlStyle"  />
    
</androidx.constraintlayout.widget.ConstraintLayout>

Add in style

<style name="XmlStyle">
    <item name="attr1">attr1: stay style Affirming in the middle</item>
    <item name="attr2">attr2: stay style Affirming in the middle</item>
</style>

Add in 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: stay Theme Affirming in the middle</item>
        <item name="attr2">attr2: stay Theme Affirming in the middle</item>
        <item name="attr3">attr3: stay Theme Affirming in the middle</item>
        <item name="attr4">attr4: stay Theme Affirming in the middle</item>
        <item name="attr5">attr5: stay Theme Affirming in the middle</item>
        <item name="attr11">@style/ThemeStyle</item>
    </style>

    <style name="ThemeStyle">
        <item name="attr1">attr1: stay Theme Style Affirming in the middle</item>
        <item name="attr2">attr2: stay Theme Style Affirming in the middle</item>
        <item name="attr3">attr3: stay Theme Style Affirming in the middle</item>
        <item name="attr4">attr4: stay Theme Style Affirming in the middle</item>
    </style>

In the above xml file, we added attr3 and attr11 in AppTheme. Attr11 is a reference, pointing to ThemeStyle. In ThemeStyle, we added attr4 attribute. There are two ways to set properties in theme: 1. Add a property (such as attr4) directly to theme; 2. Define a reference type property and point to another style. The two methods are different, and their attribute priorities are different.

Get properties in code

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);
    }
}

The context.obtainStyledAttributes method takes four parameters, among which Attributes, defAttr and defStyle are all the second parameters to tell the program where to take the attribute

R.styleable.gui indicates which attribute parameters to take.

Operation result:

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 Affirming in the middle
2020-01-22 15:03:22.133 14297-14297/com.gui.gui.custom.view V/TestView1: attr2: stay style Affirming in the middle
2020-01-22 15:03:22.134 14297-14297/com.gui.gui.custom.view V/TestView1: attr3: stay Theme Style Affirming in the middle
2020-01-22 15:03:22.134 14297-14297/com.gui.gui.custom.view V/TestView1: attr4: stay Theme Style Affirming in the middle
2020-01-22 15:03:22.135 14297-14297/com.gui.gui.custom.view V/TestView1: attr5: stay Theme Affirming in the middle

Now we modify the third construction method, which is defStyleAttr is invalid

    public TestView1(Context context, @Nullable AttributeSet attrs) {
        //this(context, attrs, R.attr.attr11);
        // Change to the following parameters
        this(context, attrs, 0);
    }

The operation results are as follows:

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 Affirming in the middle
2020-01-22 15:08:04.188 14486-14486/com.gui.gui.custom.view V/TestView1: attr2: stay style Affirming in the middle
2020-01-22 15:08:04.189 14486-14486/com.gui.gui.custom.view V/TestView1: attr3: stay def style res Affirming in the middle
2020-01-22 15:08:04.189 14486-14486/com.gui.gui.custom.view V/TestView1: attr4: stay def style res Affirming in the middle
2020-01-22 15:08:04.190 14486-14486/com.gui.gui.custom.view V/TestView1: attr5: stay Theme Affirming in the middle

 
Published 80 original articles, won praise 4, visited 10000+
Private letter follow

Posted by ryanthegecko on Wed, 22 Jan 2020 00:20:38 -0800