View (2) Custom Properties

Keywords: Android Attribute xml Mobile

There are three main ways to implement custom attributes.
Method 1: No namespace, no attrs.xml file. Get the attribute value by attrs.getAttributeResourceValue method
Method 2: Use namespace instead of attrs.xml file. Get the attribute value by attrs.getAttributeResourceValue method
Method 3: Use namespace and attrs.xml file. Get the attribute value through context.obtainStyledAttributes(attrs,R.styleable.ImageTextView).getString() method
The first method is the simplest to use, but most of the attributes obtained are strings, which can not get all kinds of values. The third method uses more steps, but can get all kinds of attributes, and can provide code error detection function.
The first method is to set the attribute value directly and get it through attrs.getAttributeResourceValue.
(1) Setting attribute values in xml files

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">
    <com.example.lenovo.custom_textview.ImageTextView1
        android:id="@+id/itv"
        iamgeBoolean="true"
        iamgeColor="#00ff00"
        iamgeDimension="100dp"
        iamgeEnum1="enum2"
        iamgeFlag="flag3"
        iamgeFloat="0.8"
        iamgeFraction="200%p"
        iamgeInteger="100"
        iamgeString="Custom Properties"
        imageReference="@drawable/trash"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

(2) Get this value in the constructor

package com.example.lenovo.custom_textview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * Created by lenovo on 2016/2/18.
 */
public class ImageTextView1 extends TextView {
    public ImageTextView1(Context context) {
        super(context);
    }
    public ImageTextView1(Context context, AttributeSet attrs) {
        super(context, attrs);
        //String representations of all attribute values can be obtained. Types of int,flat,boolea,reference,string can obtain exact values.
        String iamgeDimension = attrs.getAttributeValue(null, "iamgeDimension");
        int imageReference = attrs.getAttributeResourceValue(null, "imageReference", 0);
        if (imageReference > 0) {
            bitmap = BitmapFactory.decodeResource(getResources(), imageReference);
        }
        String iamgeColor = attrs.getAttributeValue(null, "iamgeColor");
        String iamgeString = attrs.getAttributeValue(null, "iamgeString");
        int iamgeInteger = attrs.getAttributeIntValue(null, "iamgeInteger", 0);
        float iamgeFloat = attrs.getAttributeFloatValue(null, "iamgeFloat", 0);
        boolean iamgeBoolean = attrs.getAttributeBooleanValue(null, "iamgeBoolean", false);
        String iamgeFraction = attrs.getAttributeValue(null, "iamgeFraction");
        String iamgeEnum1 = attrs.getAttributeValue(null, "iamgeEnum1");
        String iamgeFlag = attrs.getAttributeValue(null, "iamgeFlag");

        StringBuffer str = new StringBuffer();
        str.append("iamgeDimension=  " + iamgeDimension + "\n");
        str.append("imageReference=  " + imageReference + "\n");
        str.append("iamgeColor=  " + iamgeColor + "\n");
        str.append("iamgeBoolean=  " + iamgeBoolean + "\n");
        str.append("iamgeString=  " + iamgeString + "\n");
        str.append("iamgeInteger=  " + iamgeInteger + "\n");
        str.append("iamgeFloat=  " + iamgeFloat + "\n");
        str.append("iamgeFraction=  " + iamgeFraction + "\n");
        str.append("iamgeEnum1=  " + iamgeEnum1 + "\n");
        str.append("iamgeFlag=  " + iamgeFlag + "\n");
        setText(str.toString());

    }

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

    private Bitmap bitmap;

    @Override
    public void onDraw(Canvas canvas) {
        if (bitmap != null) {
            Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

            Rect target = new Rect();
            int textHeight = (int) getTextSize();
            target.left = 0;
            target.top = (int) (getMeasuredHeight() - getTextSize()) / 2 + 1;
            target.bottom = target.top + textHeight;
            target.right = (int) (textHeight * (bitmap.getWidth() / (float) bitmap.getHeight()));
            canvas.drawBitmap(bitmap, src, target, getPaint());
            canvas.translate(target.right + 2, 0);
        }

        super.onDraw(canvas);
    }


}

The second method, using its own namespace, gets the attribute value through attrs.getAttributeResourceValue.

(1) Note that in an xml file, you need to declare a namespace in the form of a package name for http://+view (in fact, the name can be arbitrarily named as long as it is a name, but generally follow this format) if it is http://com.example.activity Notice that the namespace name in xml needs to get the attribute attrs. getAttributeValue(“ http://com.example.activity The namespace name in "iamgeDimension" is the same as that in "iamgeDimension".

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mobile="http://com.example.activity"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <com.example.lenovo.custom_textview.ImageTextView2
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        mobile:iamgeBoolean="true"
        mobile:iamgeColor="@color/material_blue_grey_800"
        mobile:iamgeDimension="100dp"
        mobile:iamgeEnum1="enum2"
        mobile:iamgeFlag="flag3"
        mobile:iamgeFloat="0.8"
        mobile:iamgeFraction="200%p"
        mobile:iamgeInteger="100"
        mobile:iamgeString="Custom Properties"
        mobile:imageReference="@drawable/trash" />
</LinearLayout>

(2) Through attrs.getAttributeResourceValue, the first parameter is the namespace.

package com.example.lenovo.custom_textview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * Created by lenovo on 2016/2/18.
 */
public class ImageTextView2 extends TextView {
    public ImageTextView2(Context context) {
        super(context);
    }
    //Namespace
    private final String namespace = "http://com.example.activity";
    String tag = "ldq";
    public ImageTextView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public ImageTextView2(Context context, AttributeSet attrs) {
        super(context, attrs);

        //String representations of all attribute values can be obtained. Types of int,flat,boolea,reference,string can obtain exact values.
        String iamgeDimension = attrs.getAttributeValue(namespace, "iamgeDimension");
        int imageReference = attrs.getAttributeResourceValue(namespace, "imageReference", 0);
        if (imageReference > 0) {
            bitmap = BitmapFactory.decodeResource(getResources(), imageReference);
        }
        String iamgeColor = attrs.getAttributeValue(namespace, "iamgeColor");
        String iamgeString = attrs.getAttributeValue(namespace, "iamgeString");
        int iamgeInteger = attrs.getAttributeIntValue(namespace, "iamgeInteger", 0);
        float iamgeFloat = attrs.getAttributeFloatValue(namespace, "iamgeFloat", 0);
        boolean iamgeBoolean = attrs.getAttributeBooleanValue(namespace, "iamgeBoolean", false);
        String iamgeFraction = attrs.getAttributeValue(namespace, "iamgeFraction");
        String iamgeEnum1 = attrs.getAttributeValue(namespace, "iamgeEnum1");
        String iamgeFlag = attrs.getAttributeValue(namespace, "iamgeFlag");

        StringBuffer str = new StringBuffer();
        str.append("iamgeDimension=  " + iamgeDimension + "\n");
        str.append("imageReference=  " + imageReference + "\n");
        str.append("iamgeColor=  " + iamgeColor + "\n");
        str.append("iamgeBoolean=  " + iamgeBoolean + "\n");
        str.append("iamgeString=  " + iamgeString + "\n");
        str.append("iamgeInteger=  " + iamgeInteger + "\n");
        str.append("iamgeFloat=  " + iamgeFloat + "\n");
        str.append("iamgeFraction=  " + iamgeFraction + "\n");
        str.append("iamgeEnum1=  " + iamgeEnum1 + "\n");
        str.append("iamgeFlag=  " + iamgeFlag + "\n");
       setText(str.toString());
    }


    private Bitmap bitmap;

    @Override
    public void onDraw(Canvas canvas) {
        if (bitmap != null) {
            Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

            Rect target = new Rect();
            int textHeight = (int) getTextSize();
            target.left = 0;
            target.top = (int) (getMeasuredHeight() - getTextSize()) / 2 + 1;
            target.bottom = target.top + textHeight;
            target.right = (int) (textHeight * (bitmap.getWidth() / (float) bitmap.getHeight()));
            canvas.drawBitmap(bitmap, src, target, getPaint());
            canvas.translate(target.right + 2, 0);
        }

        super.onDraw(canvas);
    }
}
//Copy code

The third method is implemented by customizing attrs.xml. The attribute values are obtained by context.obtainStyledAttributes(attrs,R.styleable.ImageTextView).getString() method.
(1) Customize an attrs.xml file

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ImageTextView">
        <attr name="iamgeDimension" format="dimension" />
        <attr name="imageReference" format="reference" />
        <attr name="iamgeColor" format="color" />
        <attr name="iamgeString" format="string" />
        <attr name="iamgeInteger" format="integer" />
        <attr name="iamgeFloat" format="float" />
        <attr name="iamgeBoolean" format="boolean" />
        <attr name="iamgeFraction" format="fraction" />
        <attr name="iamgeEnum1">
            <enum name="enum1" value="1"></enum>
            <enum name="enum2" value="2"></enum>
        </attr>
        <attr name="iamgeFlag">
            <flag name="flag1" value="1"></flag>
            <flag name="flag2" value="2"></flag>
            <flag name="flag3" value="3"></flag>
        </attr>
    </declare-styleable>
</resources>

perhaps

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <attr name="iamgeDimension" format="dimension" />
        <attr name="imageReference" format="reference" />
        <attr name="iamgeColor" format="color" />
        <attr name="iamgeString" format="string" />
        <attr name="iamgeInteger" format="integer" />
        <attr name="iamgeFloat" format="float" />
        <attr name="iamgeBoolean" format="boolean" />
        <attr name="iamgeFraction" format="fraction" />
        <attr name="iamgeEnum1">
            <enum name="enum1" value="1"></enum>
            <enum name="enum2" value="2"></enum>
        </attr>
        <attr name="iamgeFlag">
            <flag name="flag1" value="1"></flag>
            <flag name="flag2" value="2"></flag>
            <flag name="flag3" value="3"></flag>
        </attr>

    <declare-styleable name="ImageTextView">
       <attr name="iamgeDimension"></attr>
        <attr name="imageReference"></attr>
        <attr name="iamgeColor"></attr>
        <attr name="iamgeString"></attr>
   <attr name="iamgeInteger"></attr>
        <attr name="iamgeFloat"></attr>
        <attr name="iamgeBoolean"></attr>
        <attr name="iamgeFraction"></attr>
   <attr name="iamgeEnum1"></attr>
        <attr name="iamgeFlag"></attr>
    </declare-styleable>
</resources>

Both methods can be used. There are two steps to customize attributes:

Define common attributes
Define the theme style of the control
For example, the first part of the xml file above is the public attribute, and the second part is the theme style of the custom control MyCustomView. The attributes in the theme style must be included in the public attribute. The implication is that public attributes can be used by multiple custom control theme styles.

(2) Use this property in the xml file, and pay attention to the writing specification of the namespace at this time.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ImageTextView="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">

    <com.example.lenovo.custom_textview.ImageTextView3
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    ImageTextView:iamgeDimension="100dp"
    ImageTextView:imageReference="@drawable/trash"
    ImageTextView:iamgeColor="@color/material_blue_grey_800"
    ImageTextView:iamgeString="Custom Properties"
    ImageTextView:iamgeInteger="100"
    ImageTextView:iamgeFloat="0.8"
    ImageTextView:iamgeBoolean="true"
    ImageTextView:iamgeFraction="200%p"
    ImageTextView:iamgeEnum1="enum2"
    ImageTextView:iamgeFlag="flag3"
    />
</LinearLayout>

(3) Use context.obtainStyledAttributes to get attribute values in code

Designated as a declare-styleable, and Android ATT under declare-styleable will automatically be generated as the name name of declare-styleable with "" and the corresponding attr (that is, the attribute name). As above (ImageTextView_String), we need R.leable.ImageTextView_String to get Text, which can be seen in R.java. Generate file

package com.example.lenovo.custom_textview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * Created by lenovo on 2016/2/18.
 */
public class ImageTextView3 extends TextView {
    public ImageTextView3(Context context) {
        super(context);
    }
    public ImageTextView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ImageTextView);
  // TypedArray is an array that stores resources.1.Get this array from context,attrs It's the constructor that comes in.,Corresponding attrs.xml  
   // Gets the properties defined in xml in the format of name_attribute name followed by default value
        double iamgeDimension = typedArray.getDimension(R.styleable.ImageTextView_iamgeDimension, 0);
        int imageReference = typedArray.getResourceId(R.styleable.ImageTextView_imageReference, 0);
        bitmap = BitmapFactory.decodeResource(getResources(), imageReference);
        Drawable drawable = typedArray.getDrawable(R.styleable.ImageTextView_imageReference);
        double iamgeColor = typedArray.getColor(R.styleable.ImageTextView_iamgeColor, 0);
        String iamgeString = typedArray.getString(R.styleable.ImageTextView_iamgeString);
        double iamgeInteger = typedArray.getInteger(R.styleable.ImageTextView_iamgeInteger, 0);
        double iamgeFloat = typedArray.getFloat(R.styleable.ImageTextView_iamgeFloat, 0);
        boolean iamgeBoolean = typedArray.getBoolean(R.styleable.ImageTextView_iamgeBoolean, false);

//        ImageTextView:iamgeFraction="200%"
//        ImageTextView:iamgeFraction="200%p"
//         double iamgeFraction = typedArray.getFraction(R.styleable.ImageTextView_iamgeFraction, 4, 5, 1);
//        1)If mageTextView_iamgeFraction yes200%,that result Namely:200%*48
//        2)If mageTextView_iamgeFraction yes200%p,that result Namely:200%*5 ~ 10
        double iamgeFraction = typedArray.getFraction(R.styleable.ImageTextView_iamgeFraction, 4, 5, 1);
        double iamgeEnum1 = typedArray.getInteger(R.styleable.ImageTextView_iamgeEnum1, 0);
        double iamgeFlag = typedArray.getInteger(R.styleable.ImageTextView_iamgeFlag, 0);
   // In order to maintain consistency in future use of this attribute, a signal that binds the end of the resource is returned to the resource.  
        typedArray.recycle(); //Make sure to call the recycle() method after the call is completed, otherwise this setup will affect the next use.
        StringBuffer str = new StringBuffer();
        str.append("iamgeDimension=  " + iamgeDimension + "\n");
        str.append("imageReference=  " + imageReference + "\n");
        str.append("iamgeColor=  " + iamgeColor + "\n");
        str.append("iamgeBoolean=  " + iamgeBoolean + "\n");
        str.append("iamgeString=  " + iamgeString + "\n");
        str.append("iamgeInteger=  " + iamgeInteger + "\n");
        str.append("iamgeFloat=  " + iamgeFloat + "\n");
        str.append("iamgeFraction=  " + iamgeFraction + "\n");
        str.append("iamgeEnum1=  " + iamgeEnum1 + "\n");
        str.append("iamgeFlag=  " + iamgeFlag + "\n");
        setText(str.toString());

    }

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

    private Bitmap bitmap;

    @Override
    public void onDraw(Canvas canvas) {
        if (bitmap != null) {
            Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

            Rect target = new Rect();
            int textHeight = (int) getTextSize();
            target.left = 0;
            target.top = (int) (getMeasuredHeight() - getTextSize()) / 2 + 1;
            target.bottom = target.top + textHeight;
            target.right = (int) (textHeight * (bitmap.getWidth() / (float) bitmap.getHeight()));
            canvas.drawBitmap(bitmap, src, target, getPaint());
            canvas.translate(target.right + 2, 0);
        }

        super.onDraw(canvas);
    }
}

Conclusion:

This is the use of these two registered attributes for Android, so what's the difference between them?

Here I think there are at least five points, you can find out what the difference is.

The second is compile-time error. If programmers randomly input anything, the first is error-free, and the second can support code detection.
The second way of writing is consistent with Android attribute standard, and can unify the rules of calligraphy.
The second way of writing can support data format validation. For example, if we only support integer on attrs, then we can not use strings. This is the first way that can not be achieved.
The second way of writing can provide selection operation for VIEW. For example, the ENUM we use enables the corresponding attributes of VIEW to support ENUM list, or provides BOOL and other operations with only two options.
First, all attributes must be referenced from resources (not sure if friends have any good DEMO troubles to share). Second, it can support referenced resources and direct input for operation, which brings more convenience to programming.
All these show that the second way of writing is more normative, functional and elegant.

Posted by diesel on Tue, 04 Jun 2019 13:14:55 -0700