Creating a View Class
一個設計優良的使用者介面應該和其他設計優良的類一樣,將一系列功能封裝起來,並且暴露給使用者一個簡單的介面,並且能夠做到高效的使用CPU和記憶體。
為了能夠設計一個好的自訂View,應該做到:
遵循android開發原則
可以再XML檔案找那個設定其屬性
發送可以捕獲的事件
可以相容多個android平台
Android Framework提供了一系列基類和XML節點來建立符合要求的View。這節將介紹怎麼使用Android Framework來實現view的核心功能。
Subclass a View
在Android Framework中所有能夠顯示的類都繼承自View類。自訂的類可以直接繼承View,也可以繼承View的子類,比如Button類,這麼做可以節省時間。
為了使Android Developer Tools與自訂的View相互作用,最低限度也要提供一個含有Context和AttributeSet作為參數的構造方法。這個構造方法允許layout editor來建立這個自訂View的執行個體。
classPieChartextendsView{
publicPieChart(Context context,AttributeSet attrs){
super(context, attrs);
}
}
Define Custom Attributes
通過使用Xml檔案的節點屬性控制自訂View的顯示和行為。一個好的自訂View是能夠通過XML檔案來添加和管理屬性的。
要實現這種自訂View,需要做到:
在resource檔案的 <declare-styleable>節點下定義自訂屬性
在XML布局檔案中指定屬性的值
能夠在運行過程中取到屬性的值
重新為自訂view分配器屬性值
這一段討論怎麼定義自訂屬性並且為其指定value,下一段將主要處理怎麼在運行時擷取屬性值並且重新為屬性賦值
為了定義自訂屬性,要在res/values/attrs.xml檔案的resource節點下增加<declare-styleable>節點。
下面是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>以上代碼聲明了兩個自訂的屬性,showText和labelPosition,這兩個屬性都屬於名字為PieChart的實體view。按照慣例來講,這個實體view的名字應該要與在布局檔案中生命的自訂view的名字相同。雖然沒有明確要求必須相同,但是現在很多代碼都是這樣命名的。
一旦定義完成了這些自訂屬性,你就可以再XML布局檔案中使用這些屬性,且使用方法與android內嵌屬性的使用方法是一樣的。唯一的區別就是要命名空間不同。命名空間的方法為http://schemas.android.com/apk/res/[your package name] 取代了以前的http://schemas.android.com/apk/res/android
例如,一下代碼為怎麼使用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>為了避免重複使用這麼長的URI,這個例子使用的xmlns的文法規則將其提取出來。
需要注意的是,如果要使用的view是屬於嵌套規格的,那麼使用的時候一定要加上外部view的類名。比如PieChart有一個內部類名字為PieView。如果想要使用PieView的屬性就要這樣使用com.example.customviews.charting.PieChart$PieView.
Apply Custom Attributes
當一個view被建立,所有的屬性都會讀到View的構造方法中俄AttributeSet中。但是,如果直接從AttributeSet中讀取的話,有以下缺點:
·Resource references within attribute values are not resolved
·Styles are not applied
所以,利用TypedArray的數組取代了通過AttributeSet和obtainStyledAttributes()。
Android資源編譯器做了很多工作,使得你調用obtainStyledAttributes的時候更加簡單。
對於每個 <declare-styleable>,R.java檔案都自動產生了一個attributes數組和每一個屬性在數組中的位置。你可以使用預先定義好的在attributes中的位置來從TypeArray中擷取到屬性。
下邊的代碼就是示範怎麼從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是共用資源,當使用完畢之後一定要進行回收。
Add Properties and Events
Attributes在控制view的顯示和行為方面是很強大的。但是這種方式在view初始化時只能讀。為了提供動態行為,應該為自訂屬性添加getter和setter方法。下邊的片段就是示範PieChart是怎麼暴露showText屬性的:
public boolean isShowText() {
return mShowText;
}
public void setShowText(boolean showText) {
mShowText = showText;
invalidate();
requestLayout();
}注意:setShowText方法調用了invalidate()和requestLayout()方法。這個方法是這個操作能夠正常執行的保證。當view的屬性和外觀發生變化之後,調用invalidate方法來通知系統進行重繪的操作是必須的。同樣的,當屬性發生變化時,也需要建立一個新的layout來適應當前的大小和形狀。如果忘記調用這些方法的話,產生的bug是很難被找到的。
自訂view也同樣應該支援監聽器來傳遞訊息。比如,PeiChat暴露了一個OnCurrentItemChanged的方法來通知監聽器使用者已經旋轉的映像,來產生一個新的映像。
很容易忘記暴露出屬性和事件,尤其當我們知識這個自訂View的使用者的時候。現在花些時間來定義view的介面可以減少以後維護的成本。一個好的設計原則就是暴露出所有的能夠改變自訂view的顯示和行為的屬性。
Design For Accessibility
Your custom view should support the widest range of users. This includes users with disabilities that prevent them from seeing or using a touchscreen. To support users with disabilities, you should:
· Label your input fields using the android:contentDescription attribute
· Send accessibility events by calling sendAccessibilityEvent() when appropriate.
· Support alternate controllers, such as D-pad and trackball
For more information on creating accessible views, see Making Applications Accessible in the Android Developers Guide.