一個設計良好的的自定義view應該是一個設計良好的class,它包含了不少實用的功能,讓人們更加容易使用接口。它充分利用GPU與內存的性能等等。 另外做爲一個設計良好的類,一個自定義view還應該有如下特性:html
聽從android標準java
提供能夠在layout中使用的自定義屬性android
兼顧各類人士需求(好比視力,聽力)web
兼容各類android平臺版本數組
android的sdk提供了一系列的基礎的類和xml的標記來幫助你建立一個知足你需求的自定義view。本節課將討論如何利用android的framwork來建立一個有基本核心功能的自定義view。app
android系統framwork層的view都是繼承自View這個基類。你的自定義view也能夠直接繼承自View,或者你爲了節省時間能夠繼承一個已經存在的子類,好比Button。編輯器
爲了讓Android Developer Tools 能和你的自定義view交互,你必須最少提供一個接受Context和AttributeSet爲參數的構造函數。經過這個構造函數,layout編輯器能夠建立和編輯你的自定義view的實例。(也就是能夠在未運行的時候,展現出界面)ide
class PieChart extends View { public PieChart(Context context, AttributeSet attrs) { super(context, attrs); } }
爲了向你的界面中添加一個內建的view,你須要在xml元素裏面指定,而後經過元素的屬性控制它的顯示和行爲。爲了作到這一點,你必須:函數
在<declare-styleable>資源屬性下爲你的自定義view定義屬性性能
在xml layout中指定屬性的值
在運行的時候,接受屬性的值
將接受的值應用到你的view中去
這一節討論瞭如何定義自定義的屬性與指定他們的值。下一節將處理在運行時接收與應用屬性的值。
爲了定義自定義屬性,添加<declare-styleable>資源到你的工程中。一般咱們會將這些資源放到res/values/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與lablePosition,這兩個屬性屬於styleable 實體,命名爲PieChart,styleable實體的命名一般爲了方便,和你的自定義view的名字同樣。儘管這不是一個嚴格的規定,可是不少很是流行的開源代碼的做者也是聽從這個原則。
一旦你定義了自定義屬性,你就能夠像內置的android屬性那樣來運用你的屬性。惟一的不一樣就是你的自定義屬性是屬於一個不一樣的命名空間的。他們不是屬於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這個名字賦值給了http://schemas.android.com/apk/res-auto這個命名空間。 你能夠選擇任何的同名簡化單詞來替代你的命名空間。
Note:若是你沒有使用gradle來構建你的系統,你的xlmns URI不能包含 res-auto 。這個URI比較包含完整的你的項目的名字。這個例子中,若是不是grale構建的話,URI應該爲http://schemas.android.com/apk/res/com.example.customviews
請注意你在xml中指定的你的自定義view的名字。這個名字必須是這個類完整的類路徑。若是你的自定義view是一個inner class,你必須講outer class的名字也加上。例如,這個PieChart類若是有一個inner class 叫PieView.爲了使用這個自定義view的屬性,你應該這樣寫你的tag com.example.customviews.charting.PieChart$PieView
當一個view從xml layout中建立出來後,全部的在xml tag中的屬性就會從resourse bundle中讀取出來而且傳遞給view的構造函數的參數AttributeSet.儘管咱們能夠直接從AttributeSet中讀取屬性值,可是這樣作有一些缺點。
資源的引用的屬性值沒有被分解出來
Styles沒有被應用到屬性值上
因而,咱們把AttrbuteSet傳遞給obtainStyledAttributes()這個函數。這個函數會返回一個TypedArray,這個一系列的值,通過了解引用,同時將主題樣式應用到值上。
Android的資源編譯器在你調用obtainStyledAttributes()以前,作了不少工做。遍歷res目錄中<declare-styleable>資源的時候,生成了R.java文件,這個文件包含了一個屬性id的數組與屬性在數組中的次序。你經過預先定義的常量來從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對象是一個共享的資源,因此每次使用完畢後,請及時調用recycle方法。
xml的屬性是一個很強大的控制view顯示與行爲的方式,可是它們卻只能在view初始化的時候來讀取。爲了提供動態的行爲,咱們能夠爲每個xml屬性提供get與set方法。下面代碼片斷展現瞭如何向外部提供一個get與set接口:
public boolean isShowText() { return mShowText; } public void setShowText(boolean showText) { mShowText = showText; invalidate(); requestLayout(); }
注意下,setShowText方法調用了invalidate()與requestLayout().這些調用很重要,是用來保證view的行爲是可靠的。當你修改了一些可能影響view顯示的屬性時,你必須invalidate你的view,這樣系統就能夠知道這個view須要從新繪製。一樣的,當你修改了一些影響view大小與形狀的屬性時,你必須調用requestLayout。忘記調用這個函數,可能到致使不少難以發現的bug。
自定義view也應該支持一些事件的監聽。例如,PieChart向外提供一個叫作 OnCurrentItemChanged方法,來通知監聽者用戶已經旋轉了pie chart。
咱們很容易就忘記向外提供屬性與事件監聽,尤爲是當這個自定義view只有咱們一我的使用的時候。花一些時間來定義這些view的接口,這樣能夠節省之後維護的成本花費。一個好的作法就是,將全部影響顯示與行爲的屬性都向外提供接口。
你的自定義view應該儘量支持更多的用戶。包括視力,或者行動不方便的人士。爲了支持這些人,你應該:
在你的輸入性的控件上面使用 android:contentDescription這個屬性
在合適的時間經過調用sendAccessiblityEvent發送兼容性事件
支持交叉輸入控制,好比軌跡球,D-pad
更多的關於建立兼容view的知識,請查看 Making Application Accessible