天天看點

Android自定義屬性(一):自定義屬性的使用如何自定義屬性XML中使用自定義屬性代碼中使用自定義屬性添加屬性和事件

官方文檔:https://developer.android.com/training/custom-views/create-view#java

如何自定義屬性

  • 在res/values/attr.xml檔案中添加<declare-stylable>标簽,在該标簽中添加自定義屬性
  • 在xml布局中為屬性指定值
  • 運作時檢索屬性值
  • 将檢索到的屬性值應用于視圖

示例:

1、為了自定義屬性,在項目中添加<declare-resource>資源,将該資源放置于res/values/attrs.xml。 如下是attrs.xml檔案例子:

<resources>
   <declare-styleable name="PieChart">
       <attr name="showText" format="boolean" />
       <attr name="labelPosition" format="enum">
           <enum name="left" value="0"/>
           <enum name="right" value="1"/>
       </attr>
   </declare-styleable>
</resources>
           

這段code定義了兩個屬性showText和lablePosition,屬于PieChart實體。

代碼的含義:
declare-styleable:一個屬性組,其name必須和自定義View的名字相同。
attr:代表一個單獨的屬性,format代表屬性的格式。
labelPosition屬性中定義了預設值enum
           

XML中使用自定義屬性

定義的屬性和系統的其他内置屬性一樣在xml中使用。唯一的差別是它們所屬的命名空間(namespace)不同。

内置屬性所屬的命名空間:http://schemas.android.com/apk/res/android

自定義屬性所屬命名空間:http://schemas.android.com/apk/res/[your package name]

例如,如下是如何為PieChart使用這些自定義的屬性:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews">
 <com.example.customviews.charting.PieChart
     custom:showText="true"
     custom:labelPosition="left" />
</LinearLayout>
           

xmlns:custom是加入命名空間,這個名稱可以任意更改。如果修改為xmlns:xx,則使用屬性時就是xx:showText = "true"。

注意此處的XML tag添加自定義view是完全限定名稱。如果視圖類是一個内部類,必須使用視圖外部類的名稱進一步限定它。

比如,PieChart有一個内部類叫做PieView,要使用此類中的自定義屬性,可使用tag  com.example.customviews.charting.PieChart$PieView.

自定義屬性的取值都是取決于自定義View的布局檔案中的對應的屬性的值。如showText屬性就為true,labelPosition屬性就為left。

代碼中使用自定義屬性

從XML布局建立視圖時,XML tag中的所有屬性都從資源包中讀取,并作為AttributeSet傳遞到視圖的構造函數中。雖然可以直接從AttributeSet中直接擷取,但是這樣做有一些缺點:

  • 屬性中的資源引用沒有解析
  • 樣式沒有被應用

相反,将AttributeSet傳遞給obtainStyleAttributes()。這個方法回傳一個已經解析過的資源引用和應用了樣式的TypedArray數組。

PieChart如何讀取它的屬性:

public PieChart(Context context, AttributeSet attrs) {
   super(context, attrs);
   TypedArray a = context.getTheme().obtainStyledAttributes(
        attrs,
        R.styleable.PieChart,
        0, 0);

   try {
       mShowText = a.getBoolean(R.styleable.PieChart_showText, false);
       mTextPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);
   } finally {
       a.recycle();
   }
}
           

注意,TypedArray對象是共享資源,必須使用後進行回收。

添加屬性和事件

屬性是控制視圖行為和顯示的有效方法,但是隻能在視圖初始化後時讀取它們。要提供動态行為,需要為每個自定義屬性建立gettter和setter方法。如下代碼,展示了PieChart如何公開屬性showText:

public boolean isShowText() {
   return mShowText;
}

public void setShowText(boolean showText) {
   mShowText = showText;
   invalidate();
   requestLayout();
}
           

setShowText函數裡調用了invalidate()和requestLayout()函數,這兩個函數對于視圖能正常地顯示有至關重要的作用。如果改變了可能影響顯示的屬性,必須廢止(invalidate)目前視圖,這樣系統才會知道需要重繪。同樣,如果一個可能影響視圖size或shape的屬性改變了,需要申請新的布局。如果沒有調用這個兩個方法,可能會出現難以發現的Bug。

自定義視圖應該要定義事件監聽器來通知重要事件。例如,PieChart有一個自定義方法OnCurrentItemChanged來通知listener,使用者旋轉了這個Pie chart以關注新的Chart Slice。

繼續閱讀