Android 會根據基礎版面配置類別 View
和 ViewGroup
,提供複雜且強大的元件化模型來建構 UI。平台包含各種預先建構的 View
和 ViewGroup
子類別,分別稱為小工具和版面配置,可用來建構 UI。
部分可用小工具清單包括 Button
、TextView
、EditText
、ListView
、CheckBox
、RadioButton
、Gallery
、Spinner
,以及專用 AutoCompleteTextView
、ImageSwitcher
和 TextSwitcher
。
可用的版面配置包括 LinearLayout
、FrameLayout
、RelativeLayout
等。如需更多範例,請參閱常見版面配置。
如果預先建構的小工具或版面配置都不符合您的需求,您可以建立自己的 View
子類別。如果只需要對現有的小工具或版面配置進行微幅調整,可將小工具或版面配置設為子類別,並覆寫其方法。
建立自己的 View
子類別,即可精確控制畫面元素的外觀和功能。為了讓您瞭解使用自訂檢視的控制項,以下列舉一些自訂檢視區塊的用途:
-
您可以建立完全自訂的
View
類型,例如使用 2D 圖形轉譯的「音量控制」旋鈕,看起來像類比電子控制項。 -
您可以將一組
View
元件合併為一個新的元件,例如建立下拉式方塊 (彈出式清單和任意輸入文字欄位的組合)、雙窗格選取器控制項 (左側和右側窗格包含清單,每個窗格內含可重新指派哪個項目的清單),依此類推。 -
您可以覆寫
EditText
元件在螢幕上的顯示方式。 NotePad 範例應用程式會使用這項有效效果來建立劃底線的記事本頁面。 - 您可以擷取其他事件 (例如按鍵操作),並透過自訂方式 (例如遊戲) 處理。
以下章節說明如何建立自訂檢視並在應用程式中使用。如需詳細的參考資訊,請參閱 View
類別。
基本方法
以下概略說明建立自己的 View
元件時需要知道的資訊:
-
使用自己的類別擴充現有的
View
類別或子類別。 -
覆寫父類別中的某些方法。要覆寫的父類別方法以
on
開頭,例如onDraw()
、onMeasure()
和onKeyDown()
。這與Activity
或ListActivity
中的on
事件類似,您可以覆寫生命週期和其他功能掛鉤。 - 使用新的擴充功能類別。完成後,您就能使用新的擴充功能類別,取代原本的檢視畫面。
完全自訂元件
您可以建立完全自訂的圖形元件,以想要的方式顯示。假設您需要看起來像舊類比量計的圖形 VU 計量器,或是伴唱文字檢視區塊,可在您唱卡拉 OK 機時跟著彈跳的球在文字上移動。無論您如何合併這些內建元件,都可能希望這些內建元件無法執行的功能。
幸好,您可以建立元件,讓元件看起來和行為都符合您的需求,但僅限於您的想像力、螢幕尺寸,以及可用的處理能力。請注意,應用程式可能需要在某種程度上執行應用程式所需的電力,而且效能可能會遠低於您的桌上型電腦工作站。
如要建立完全自訂的元件,請考慮以下事項:
-
您可以擴充的最常見檢視區塊為
View
,因此通常先擴充這個檢視區塊,以便建立新的超級元件。 - 您可以提供建構函式,以從 XML 擷取屬性和參數,您可以使用自己的屬性和參數,例如 VU 計量器的顏色和範圍,或是針狀的寬度和阻力。
- 您可能需要建立自己的事件監聽器、屬性存取子和修飾符,以及在元件類別中建立更複雜的行為。
-
在大部分的情況下,如果您想讓元件顯示某些內容,通常也會想覆寫
onMeasure()
,而且可能需要覆寫onDraw()
。雖然兩者都有預設行為,但預設onDraw()
不會執行任何動作,而預設的onMeasure()
一律會設定 100x100 的大小,這是我們可能不想要的。 -
您也可以視需要覆寫其他
on
方法。
擴充 onDraw() 和 onMeasure()
onDraw()
方法提供 Canvas
,您可以在這個位置實作任何所需項目:2D 圖形、其他標準或自訂元件、樣式化文字,或者您可以想到的任何東西。
onMeasure()
有點複雜。onMeasure()
是元件及其容器之間轉譯合約的關鍵要素。必須覆寫 onMeasure()
,才能有效且準確地回報其所含零件的測量結果。這會稍微複雜,根據父項的限制要求 (會傳遞至 onMeasure()
方法),以及要求在計算後使用測量的寬度和高度呼叫 setMeasuredDimension()
方法。如果您不透過覆寫的 onMeasure()
方法呼叫此方法,會導致在測量時發生例外狀況。
大致來說,實作 onMeasure()
看起來會像這樣:
-
系統以寬度和高度規格呼叫覆寫的
onMeasure()
方法,這類規格會視為針對您產生的寬度和高度測量結果限制的要求。widthMeasureSpec
和heightMeasureSpec
參數都是代表尺寸的整數代碼。如需這些規格所要求限制的完整參考資料,請參閱「View.onMeasure(int, int)
」下方的參考說明文件。這份參考說明文件也解釋了整個評估作業。 -
元件的
onMeasure()
方法會計算顯示元件所需的測量寬度和高度。它必須盡量保持在傳入的規格內,但可以超過規格要求。在這種情況下,父項可以選擇要執行的操作,包括裁剪、捲動、擲回例外狀況,或要求onMeasure()
再試一次 (可能使用不同的測量規格)。 -
計算寬度和高度時,使用算出的測量值呼叫
setMeasuredDimension(int width, int height)
方法。否則將視為例外狀況。
以下摘要說明架構在檢視區塊上呼叫的其他標準方法:
類別 | 方法 | 說明 |
---|---|---|
創作 | 建構函式 | 透過程式碼建立檢視畫面時,系統會呼叫一種形式的建構函式,然後在從版面配置檔案加載檢視畫面時呼叫該表單。第二種形式會剖析並套用版面配置檔案中定義的屬性。 |
|
在從 XML 加載檢視區塊及其所有子項之後呼叫。 | |
版面配置 |
|
呼叫此項以確定該檢視區塊及其所有子項的大小要求。 |
|
在此檢視區塊必須向其所有子項指派大小和位置時呼叫。 | |
|
當這個檢視區塊的大小變更時,會呼叫此方法。 | |
繪圖 |
|
當檢視區塊必須轉譯其內容時,會呼叫此方法。 |
事件處理 |
|
當發生按鍵向下事件時呼叫。 |
|
發生按鍵向上事件時呼叫。 | |
|
在發生軌跡球動作事件時呼叫此方法。 | |
|
在發生觸控螢幕動作事件時呼叫。 | |
突顯重點 |
|
當檢視區塊獲得或失去焦點時呼叫。 |
|
當包含檢視區塊的視窗獲得或失去焦點時呼叫。 | |
附加 |
|
在檢視區塊附加至視窗時呼叫。 |
|
當檢視區塊從視窗卸離時呼叫。 | |
|
在包含檢視區塊的視窗顯示設定變更時呼叫。 |
複合控制項
如果您不想建立完全自訂的元件,而是想結合一組現有控制項的可重複使用元件,那麼建立複合元件 (或複合控制項) 是最好的做法。總而言之,這會將多個更不可分割的控制項或檢視畫面,合併成一個邏輯項目群組,可視為單一項目。舉例來說,下拉式方塊可以是單行 EditText
欄位,以及鄰近按鈕 (已附加彈出式清單) 的組合。如果使用者輕觸按鈕並選取清單中的內容,該按鈕就會填入 EditText
欄位,但他們也可以視需要直接在 EditText
中輸入內容。
在 Android 中,您可以使用另外兩種檢視畫面來達到此效果:Spinner
和 AutoCompleteTextView
。無論如何,這個下拉式方塊的概念就是很好的例子。
如要建立複合元件,請按照下列步驟操作:
-
和
Activity
一樣,請使用宣告式 (基於 XML) 方法來建立內含的元件,或是透過程式輔助方式以程式輔助方式建立元件。常見的起點是某種種類的Layout
,因此請建立擴充Layout
的類別。如果是下拉式方塊,則可以使用水平方向的LinearLayout
。您可以為內部其他版面配置建立巢狀結構,讓複合元件可以任意複雜且結構化。 -
在新類別的建構函式中,擷取父類別所需的參數,並先將其傳遞至父類別建構函式。然後,您可以在新元件中設定其他檢視畫面。您可以在這裡建立
EditText
欄位和彈出式清單。您可以在 XML 中引入自己的屬性和參數,讓建構函式可以提取及使用。 -
或者,您也可以為內含的檢視區塊可能產生的事件建立事件監聽器。範例為清單項目點擊事件監聽器的事件監聽器方法,可在選取清單時更新
EditText
的內容。 -
您也可以選擇使用存取子和修飾符自行建立屬性。例如,讓
EditText
值的初始設定在元件中設定,並視需要查詢其內容。 -
視需要覆寫
onDraw()
和onMeasure()
。擴充Layout
時通常不需要這麼做,因為版面配置具有可能正常運作的預設行為。 -
視需要覆寫其他
on
方法,例如onKeyDown()
,例如:輕觸特定鍵時,從下拉式方塊的彈出式清單中選擇特定預設值。
使用 Layout
做為自訂控制項的基礎的優點包括:
- 您可以使用宣告式 XML 檔案指定版面配置,就像使用活動畫面一樣;也可以透過程式輔助方式建立檢視畫面,並透過程式碼將其嵌入版面配置中。
-
onDraw()
和onMeasure()
方法和大多數其他on
方法皆具有適當的行為,因此您不必覆寫這些方法。 - 您可以快速建構任何複雜的複合檢視區塊,並將其視為單一元件重複使用。
修改現有檢視畫面類型
如有與所需元件類似的元件,您可以擴充該元件,並覆寫要變更的行為。您可以利用完全自訂的元件執行所有操作,但從 View
階層中更專業的類別開始,您就可以取得一些行為,免費執行您想要執行的操作。
例如,NotePad 範例應用程式示範了使用 Android 平台的許多面向。其中之一是擴充 EditText
檢視區塊,以建立標有線條的記事本。這並不是一個完美的範例,而且用於執行此操作的 API 可能會改變,但這是提供原則。
如果您還沒將 NotePad 範例匯入 Android Studio,可以使用提供的連結查看原始碼。請特別留意 NoteEditor.java
檔案中的 LinedEditText
定義。
在這個檔案中,需要留意以下事項:
-
定義
該類別的定義如下:
public static class LinedEditText extends EditText
LinedEditText
定義為NoteEditor
活動中的內部類別,但為公開類別,因此可從NoteEditor
類別外部以NoteEditor.LinedEditText
的形式存取。此外,
LinedEditText
為static
,因此不會產生所謂的「合成方法」,用於存取父項類別的資料。這表示它的行為會做為獨立類別,而不是與NoteEditor
高度相關的類別。如果內部類別不需要從外部類別存取狀態,這個方式可以更簡潔地建立內部類別。這樣可以減少產生的類別,並方便其他類別使用。LinedEditText
會擴充EditText
,也就是在這種情況下要自訂的檢視畫面。完成後,新類別即可取代一般的EditText
檢視區塊。 -
類別初始化
如同往常,系統會先呼叫父類別。這不是預設建構函式,但屬於參數化建構函式。當從 XML 版面配置檔案加載時,系統會使用這些參數建立
EditText
。因此,建構函式也必須擷取這些元素,並將其傳遞至父類別建構函式。 -
覆寫的方法
這個範例僅覆寫
onDraw()
方法,但您可能需要在建立自訂元件時覆寫其他方法。在本範例中,覆寫
onDraw()
方法後,即可在EditText
檢視畫布上繪製藍線。畫布會傳遞至覆寫的onDraw()
方法。系統會在方法結束之前呼叫super.onDraw()
方法。必須叫用父類別方法。在這種情況下,請在繪製要納入的線條後,在最後叫用。 -
自訂元件
既然您已經擁有自訂元件,該怎麼運用呢?在記事本範例中,會直接透過宣告式版面配置使用自訂元件,因此請查看
res/layout
資料夾中的note_editor.xml
:<view xmlns:android="http://schemas.android.com/apk/res/android" class="com.example.android.notepad.NoteEditor$LinedEditText" android:id="@+id/note" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:padding="5dp" android:scrollbars="vertical" android:fadingEdge="vertical" android:gravity="top" android:textSize="22sp" android:capitalize="sentences" />
自訂元件建立為 XML 中的一般檢視區塊,並使用完整套件指定類別。系統會使用
NoteEditor$LinedEditText
標記法參照您定義的內部類別,這是在 Java 程式設計語言中參照內部類別的標準方法。如果自訂檢視區塊元件未定義為內部類別,您可以使用 XML 元素名稱宣告檢視區塊元件,並排除
class
屬性。例如:<com.example.android.notepad.LinedEditText id="@+id/note" ... />
可以看到,
LinedEditText
類別現已成為獨立的類別檔案。如果類別以巢狀結構嵌入NoteEditor
類別,這項技巧將無法運作。定義中的其他屬性和參數是指傳遞至自訂元件建構函式,再傳遞至
EditText
建構函式的參數和參數,因此它們與您在EditText
檢視畫面使用的參數相同。您也可以自行新增參數。
根據您的需求,建立自訂元件十分複雜。
更複雜的元件可以覆寫更多 on
方法,並引入其專屬的輔助方法,大幅自訂其屬性和行為。唯一的限制,就是您的想像力
以及元件需要執行的操作