android提供了精巧和有力的組件化模型構建用戶的UI部分。主要是基于布局類:View和ViewGroup。在此基礎上,android平 臺提供了大量的預制的View和ViewGroup子類,即布局(layout)和窗口小部件(widget)。可以用它們構建自己的UI。
如果沒有符合你需求的預制窗口小部件,你可以創建自己的視圖子類。如果只是對已存在的窗口小部件或者布局做小的調整,只需繼承該類,覆蓋相關的方法。
創建你自己的View子類可以更精確控制視圖元素的外觀和功能。
- 可創建完整的自定義渲染視圖類型,比如創建一個2d的控制條;
- 可將一組視圖組件合成為一個新的單一組件,比如雙選的列表,選擇省和市;
- 覆蓋EditText組件,比如notepad tutorial中的示例;
- 捕捉其他事件比如按鍵事件,并執行自定義的處理方式,比如在游戲中。
基本方法
總的來說,創建自定義的視圖組件步驟是:
- 創建自己的類,繼承已經存在的View類或者子類;
- 覆蓋超類的一些方法。這些超類的方法一般以“on”開頭,比如onDraw()方法等等;
- 使用新創建的擴展類。一旦完成,你的新擴展類就可以用于所有View使用的地方。
注意:擴展類可以定義為內部類,在你創建的Activity類之中。這很有用,因為這樣可以控制外界的訪問,但是這不是必須的,因為你可能需要一個public的自定義View類供更廣泛的使用。
完全自定義組件
完全自定義的組件可以創建圖形組件顯示在你需要的任何地方。
步驟如下:
- 可以繼承的最通用的視圖類是View,可以繼承它創建自定義的組件超類;
- 可以提供構造方法,并通過xml文件獲取屬性值和參數;
- 創建自己的事件監聽器,屬性訪問器和編輯器等等;
- 一般情況下會覆蓋onMeasure()方法和onDraw()方法,這會讓組件顯示一些東西。如果都用默認的行為,onDraw()方法不做任何事情,onMeasure()方法設置一個100×100的區域;
- 根據需求覆蓋其他on…方法。
擴展onDraw()和onMeasure()方法
onDraw()方法提供給你一個Canvas對象,在它之上可以實現任何你想要的東西,通過2d圖形api。比如其他標準的后者自定義的組件,風格化的文字后者其他。
注意:這里不提供3d圖形api的支持。如果你需要3d圖形支持,必須繼承SurfaceView而不是View,并且通過單獨的線程畫圖??梢酝ㄟ^GLSurfaceViewActivity實例查看詳細信息。
onMeasure()方法有些麻煩。該方法是在容器和自定義組件之間渲染的重要部分。該方法覆蓋,要高效率的和精確的報告被包含區域的測量值。
總的來看,實現onMeasure()方法類似如下步驟:
- 調用已經覆蓋的onMeasure()方法,傳遞長和寬規范參數;
- 自定義組件在onMeasure()方法中計算需要渲染的組件的長和寬,應該在規范參數的范圍內;
- 一旦長和寬計算出來,必須調用setMeasuredDimension(int width, int height)方法,這步失敗會導致異常的拋出。
一個自定義視圖的示例
自定義視圖的示例,見:LabelView
該示例演示了一些自定義組件的不同方面:
- 繼承View類,用于完全自定義組件;
- 參數化的構造方法,提供更多的參數,定義在xml文件中;
- 標準的公開方法,用于設置標簽,比如setText()方法等;
- 覆蓋onMeasure方法確定渲染的組件尺寸;
- 覆蓋onDraw方法,在提供的canvas中畫標簽。
可以找到對示例的一些使用,在custom_view_1.xml文件中。
該示例運行效果:
android示例是混在一起的,比較亂,我這里改寫了一下,只有相關示例的代碼和配置。看起來比較簡單:
http://easymorse.googlecode.com/svn/tags/android.customer.view.demo_1.0
合成控制器
合成控制器,即不是完全自定義一個新的視圖組件,而是,將現有的原子級控制器(控件?)或者視圖組件組合在一起,處理共同的業務邏輯。比如,一個combo box可以被看做,一個單行的EditText和一個相鄰的按鈕,帶一個彈出列表。
在android中還有很多其他的示例,比如Spinner,AutoComleteTextView。
創建合成組件的步驟:
- 通常的起始步驟是,創建某種類型的Layout,即創建一個類繼承一個Layout。比如上述的combo box,可能會使用到基于垂直布局的LinearLayout。其他布局也可以嵌套在其中,因此合成組件可以任意復雜結構。和activity類似,你可 以用基于xml的聲明方式創建容器組件,也可以嵌入到程序代碼中;
- 在新類的構造方法中,得到超類所需的參數,并傳遞給超類的構造方法。另外,也可設置其他在這個心組件當中的視圖組件,比如創建一個EditText和PopupList。注意,你也可以引入自己的參數和屬性到xml文件中,這樣會被取出并用于你的構造方法;
- 還可以創建事件監聽器,用于容器中的視圖組件,比如一個監聽器方法,用于處理列表點擊的監聽器,更新EditText的文本內容;
- 創建自己的屬性訪問器和編輯器,比如,EditText的值可以在組件中初始設置,并能在需要的時候獲取它的值;
- 在繼承Layout類時,不需要覆蓋onDraw()和onMeasure()方法,因為它們可能已經符合你的要求,當然,也可以覆蓋它們實現自己特定的需求;
- 可能需要覆蓋其他on…方法,比如onKeyDown()方法。
總之,使用Layout作為基礎合成自定義的控件,有一些優點:
- 可以通過xml文件的方式聲明指定的布局,和activity類似,或者可以通過編程的方式嵌入到你的代碼中;
- onDraw()方法和onMeasure()等一般可適合需求,因此不必一定要覆蓋它們;
- 可以快速的構建任何復雜的合成視圖,重用它們為一個單一的組件。
合成控件的示例
在ApiDemos示例中,演示了SpeechView,它繼承了LinearLayout,并創建了一個組件,用于顯示談話中的引號。相關的類見:
samples/ApiDemos/src/com/example/android/apis/view/List4.java
samples/ApiDemos/src/com/example/android/apis/view/List6.java
List4示例截圖,見:
List6示例截圖,可以點擊條目,出現內容,見:
修改已存在的視圖類型
如果已存在的視圖組件已經和你的需求相差不遠,你可以只是簡單的擴展該組件,只覆蓋需要改變的行為。
比如示例中的NotePad應用(platforms/android-1.5/samples/NotePad)。
效果如下:
在文本框視圖組件(EditText)基礎上,增加了橫線。
本文主要參考:
http://developer.android.com/guide/topics/ui/custom-components.html