基於布局類View和ViewGroup的準系統,Android為建立自己的UI介面提供了先進和強大的定製化模式。首先,平台包含了各種預置的View和ViewGroup子類---Widget和layout,可以使用它們來構造自己的UI介面。
部分的可以利用的widget包括:Button、TextView、EditText、ListView、CheckBox、RadioButton、Gallery、Spinner、以及比較特殊用途的AutoCompleteTextView、ImageSwitcher和TextSwitcher。
其中可利用的布局是:LinearLayout、FrameLayout、RelativeLayout以及其他的布局。更多的例子請看“共通布局對象”。http://developer.android.com/guide/topics/ui/layout-objects.html
如果遇到了沒有預置的widget或layout的需求,可以建立自己的View子類。如果只需要對既存的widget或layout進行小的調整,那麼只需簡單的繼承widget或layout,並且重寫它們的方法。
建立自己的View子類,以便能夠精準的控制螢幕元素的外觀和功能。以下是用定製View對象來實現這種控制想法的一些例子:
1. 建立一個完全的定製化渲染的View類型,如用類似類比電子控制的2D圖形來渲染的音量控制按鈕。
2. 把一組View組件組合成一個新的單一組件,製作一些像ComboBox(一個下拉式清單和文本輸入欄位的組合)、雙面板選取器(左右兩個列表面板,右邊的列表面板中的項目與左邊列表面板中的一個項目相關聯)等組件。
3. 重寫一個EditText組件在螢幕上的渲染的方法。
4. 捕獲一些像按鍵一樣的事件,並在某些定製的方法中處理它們(如遊戲)。
基本方法
以下是建立自訂View組件需要要瞭解基本概要:
1. 自訂的View類要繼承一個既存的View類或其子類;
2. 在子類重寫父類的一些方法。要覆寫的父類方法是用‘on’開頭的,例如,onDraw()、onMeasure()和onKeyDown()等,這有點類似於重寫Activity或ListActivity的生存周期回調的on…事件。
3. 使用新的擴充類,一旦完成,新擴充的類就能被用於替換基本的View對象。
提示:擴充類能夠作為使用它們的Acticity的內部類來定義。這樣對控制對它們的訪問是有益的,當然可以建立一個新的公用的View類,這樣就可以在應用程式範圍內來使用。
完全定製化的組件
完全定製化的組件能夠用於建立你所期望的顯示效果的圖形化組件。可以是看上去像舊的類比儀錶的圖形化VU儀錶,或者是一個長的歌詞視圖,有一個跳動的球沿著歌詞移動,以便跟著這卡拉OK機歌唱,這兩種情況,無論如何組織內建的組件都無法滿足要求。
幸運的是,能夠使用任意自己喜歡的方法來建立組件的外觀和行為,唯一的限制就是你的想象力、螢幕的尺寸和可利用的處理能力(因為應用程式最終可能運行在比案頭工作站處理能力要弱的裝置上)。
以下是建立完全定製組件的步驟:
1. 毋庸置疑,能夠擴充的最通用的視圖是View類,因此通常是繼承這個View類來建立自己的新的組件;
2. 提供一個能夠從XML中擷取屬性和參數的構造器,並且也能夠使用自己屬性和參數(如VU儀錶的顏色和範圍,指標的寬度和阻尼等);
3. 建立組件中可能的事件監聽器、屬性訪問器和修飾符以及儘可能準確的行為等;
4. 覆寫onMeasure()回調方法,如果想要組件顯示一些東西,也要覆寫onDraw()回調。雖然它們都有預設的行為,onDraw()回調預設什麼也不做,onMeasure()方法預設的要設定組件的尺寸為100x100;
5. 覆寫其他的需要on…方法。
擴充onDraw()和onMeasure()
onDraw()方法會把能夠實現的任何想要的東西放到一個Canvas對象上,如2D圖形、標準或定製的組件、樣式化的文本、或其他任何能夠想到的東西。
注意:View類不能使用3D圖形。如果要使用3D圖形,必須繼承SurfaceView類,而不是View類,並且要在一個獨立的線程中描畫。
onMeasure()方法有點複雜,它是組件和它的容器之間的渲染約束的關鍵區段。覆寫onMeasure(),以便準確高效的報告組件被包含部分的尺寸。由於來自父容器限制的要求,使得尺寸的測量有些複雜,並且組件的尺寸一旦被計算完成,就要調用setMeasureDimension()方法來儲存測量的寬度和高度。如果在onMeasure()方法中調用setMeasureDimension()方法失敗,這個結果在測量時將是一個異常的值。
在上層看,實現onMeasure()方法的步驟如下:
1. 要用父容器的寬度和高度的計量規格來調用被覆寫的onMensure()方法(widthMeasureSpec和heightMeasureSpec參數都是代表了尺寸的整數),這兩個參數應該作為產生組件的寬度和高度的約束要求。對於這些規格約束類型的完整說明可以在View類說明的View.onMeasure(int,int)方法中找到。
2. 組件的onMeasure()方法應該計算用於渲染組件所需的尺寸(寬度和高度)。組件應該盡量保留在被傳入的規格範圍內,儘管它能夠選擇超出規格範圍(在這種情況下,父容器能夠選擇做的事情包括:裁剪、滾動、拋出異常、或者要求onMeasure()方法用不同的尺寸規格再試)。
3. 一旦組件的寬度和高度被計算完成,就必須調用setMeasuredDimension(int width, int height)方法來儲存計算結果。不這樣做就會拋出一個異常。
下表是framework調用View類的其他標準方法:
分類 |
方法 |
說明 |
Creation |
Constructors |
構造器的調用有兩種類型:1.在代碼中建立View對象;2.用布局檔案填充View對象。第二種類型應該解析和應用布局檔案中的任何屬性定義。 |
onFinishInflate() |
View對象和它的所有子物件都用XML填充完之後,調用這個方法。 |
Layout |
onMeasure(int, int) |
調用這個方法決定View對象及其所有子物件的尺寸要求。 |
onLayout(boolean,int,int,int,int) |
當View對象給它的所有子物件分配尺寸和位置時,調用這個方法。 |
onSizeChanged(int,int,int,int) |
當View對象的尺寸發生改變時,調用這個方法。 |
Drawing |
onDraw(Canvas) |
當View對象渲染它的內容時,調用這個方法。 |
Event |
onKeyDown(int,KeyEvent) |
當一個鍵的按下事件發生時,調用這個方法 |
onKeyUp(int,KeyEvent) |
當一個鍵彈起事件發生時,調用這個方法 |
onTrackballEvent(MotionEvent) |
當滑鼠軌跡球滾動事件發生時,調用這個方法。 |
onTouchEvent(MotionEvent) |
當觸屏事件發生時,調用這個方法。 |
Focus |
onFocusChanged(boolean,int,Rect) |
當View對象擷取或失去焦點時,調用這個方法。 |
onWindowFocusChanged(boolean) |
當包含View對象的視窗獲得或失去焦點時,調用這個方法。 |
Attaching |
onAttachedToWindow() |
當View對象被綁定到一個視窗時,調用這個方法。 |
onDetachedFromWindow() |
當View對象被從它的視窗中分離的時候,調用這個方法。 |
onWindowVisibilityChanged(int) |
當包含View對象的視窗的可見度發生改變時,調用這個方法。 |
|
|
|
定製View的例子
在API Demos中提供了一個定製的View對象的例子:CustomView。這個定製的View定義在LabelView類中。
LabelView樣本展示了很多定製組件的不同特徵:
1.
繼承View類的完全定製化的組件;
2. 參數化的帶有View填充參數(在XML中定義的參數)方式構造View對象。有一些填充參數使用通過這個View的父類傳遞過來的,還有一些用於labelView對象而定義的定製的屬性;
3. 你所期望看到的標準的公用類型的方法,如setText()、setTextSize()、setTextColor()等等;
4. 一個重寫的onMeasure()方法,它決定和設定了組件的渲染尺寸。(注意:在LabelView類中,實際的工作是由一個私人的measureWidth()方法來做的。)
5. 一個重寫的onDraw()方法,它在提供的Canvas上描畫標籤。
從這個樣本的custom_view_1.xml中,能夠看到一些LabelView定製View的用法。實際上,可以看到android:命名空間參數和定製的app:命名空間的組合。這些app:參數是LabelView類所承認的並用於工作的一些定製化的屬性,並且這些參數在樣本的R資源定義類的styleable內部類中被定義。