Android 屬性自定義及使用獲取淺析


一、概述

相信你已經知道,Android 可使用 XML 標簽語言進行界面的定義。每個標簽中有一個一個的屬性,這些屬性有相應的屬性值。例如:

<cn.neillee.composedmenu.RotatingArcMenu
	android:id="@+id/ram2"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:background="?attr/barBgColor"
	app:position="left_bottom"
	app:radius="150dp"/>

有兩點可以注意到:

  • 其一,在某個自定義 ViewGroup 中,有兩個自定義屬性 positionradius,與其他屬性不同的是,這兩個屬性的命名空間為 app

  • 其二,系統屬性 background 的屬性值為 ?attr/barBgColor

二、詳細介紹

2.1 自定義屬性

這里介紹

app:position="left_bottom"
app:radius="150dp"

的使用。

自定義屬性常見於自定義的 View 中,讓我們還是以概述中的代碼作為例子。自定義屬性及其屬性值在 /values/attr.xml 中有如下定義:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="position">
        <enum name="left_top" value="0"/>
        <enum name="left_bottom" value="1"/>
        <enum name="right_top" value="2"/>
        <enum name="right_bottom" value="3"/>
    </attr>
    <attr name="radius" format="dimension"/>

    <declare-styleable name="ComposedMenu">
        <attr name="position"/>
        <attr name="radius"/>
    </declare-styleable>
</resources>

在該文件中,枚舉了 position 有四個屬性值,並為每個屬性值提供了不同的 value 值作區分。而 radius 定義為 dimension 引用,表示其值須為 dimension 類型的值。類似地,還有如有其他類型,參考文章 【Android】Android自定義屬性,attr format取值類型

接下來如何獲取自定義屬性值就成了關鍵。我在自定義 ViewGroup 中使用如下代碼獲取到用戶在 layout 文件中,自定義 ViewGroup 標簽下使用到的值。

private static final int LEFT_TOP = 0;
private static final int LEFT_BOTTOM = 1;
private static final int RIGHT_TOP = 2;
private static final int RIGHT_BOTTOM = 3;

protected static final int DEFAULT_RADIUS = 150;
protected static final int DEFAULT_POSITION = RIGHT_BOTTOM;

protected int mRadius;

...
public RotatingArcMenu(Context context, AttributeSet attrs, int defStyleAttr) {
	TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ComposedMenu, defStyleAttr, 0);
	int pos = a.getInt(R.styleable.ComposedMenu_position, DEFAULT_POSITION);
	mRadius = (int) a.getDimension(R.styleable.ComposedMenu_radius, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_RADIUS, getResources().getDisplayMetrics()));
	a.recycle();// 使用完后記得回收
}

2.2 獲取系統屬性

這里介紹 android:background="?attr/barBgColor" 屬性的定義與獲取。

我之所以如此定義,是為了使得 背景色 能夠隨着應用的主題切換而變化,最簡單的例子就是 夜間模式
首先,我在 values/attr.xml 文件中對 barBgColor 進行定義:

<?xml version="1.0" encoding="utf-8"?>
<resources>
	...
    <attr name="barBgColor" format="color"/>
</resources>

其次,在 values/styles.xml 中對該屬性值進行了定義:

<resources>

    <style name="AppDayTheme" parent="Theme.AppCompat.Light.NoActionBar">
		<item name="barBgColor">@color/ZHIHUBlue</item>
	</style>
	<style name="AppNightTheme" parent="Theme.AppCompat.Light.NoActionBar">
		<item name="barBgColor">#263238</item>
	</style>
</resources>

最后,我在控件的屬性中對該屬性值進行了使用

<cn.neillee.composedmenu.RotatingArcMenu
	android:id="@+id/ram2"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:background="?attr/barBgColor"
	app:position="left_bottom"
	app:radius="150dp"/>

需要說明的是,可以不再控件屬性中使用自定義的屬性值,可在代碼中進行獲取與設置。如:

TypedValue typedValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.barBgColor, typedValue, true);
mRotatingArcMenu.setBackgroundColor(typedValue.data);

這里使用到了 TypedValue 這個類。

2.3 關於 TypedValue

詳細介紹見官網:
https://developer.android.com/reference/android/util/TypedValue.html

此處我僅對我在上一小節中的使用做簡單介紹。在使用過程中,我觀察到在不同主題下,TypedValue 讀取到的值如下:

在 DayTheme 中,由於我定義的是 @color/ZHIHUBlue ,對color的引用即 resourceId。因此,typedValue.resourceId 有值,且直接等效於 R.color.ZHIHUBlue,typedValue.type=TYPE_INT_COLOR_RGB8,表示 typedValue.data 有值,為8位的顏色代碼值(#rrggbb)。

在 NightTheme 中,由於我定義的是 #263238,顏色代碼值。因此,TypedValue.resourceId 無值,但 typedValue.type=TYPE_INT_COLOR_RGB8,表示 typedValue.data 有值,為8位的顏色代碼(#rrggbb)。

此文在我的 Github Pages 上同步發布,地址為:Android-屬性自定義及使用獲取淺析


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM