版面配置   Android Jetpack 的一部分。

版面配置定義了應用程式使用者介面的結構,例如活動。版面配置中的所有元素都使用 ViewViewGroup 物件階層建立。View 通常會擷取使用者可查看並進行互動的內容。而 ViewGroup 是一個隱藏容器,用於定義 View 和其他 ViewGroup 物件的版面配置結構,如圖 1 所示。

圖 1. 插圖:定義 UI 版面配置的檢視區塊階層

View 物件通常稱為「小工具」,可能是多個子類別中的一個,例如 ButtonTextViewViewGroup 物件通常稱為「版面配置」,可能是提供不同版面配置結構的眾多類型中的一個,例如 LinearLayoutConstraintLayout

您可以透過下列兩種方式宣告版面配置:

  • 在 XML 中宣告 UI 元素。Android 提供符合 View 類別和子類別的簡單 XML 詞彙,例如用於小工具和版面配置的詞彙。

    您也可以利用 Android Studio 的版面配置編輯器,透過拖曳式介面建立 XML 版面配置。

  • 在執行階段將版面配置元素執行個體化。您的應用程式可以透過程式輔助方式建立 View 和 ViewGroup 物件 (以及控管其屬性)。

透過 XML 宣告使用者介面可以讓您分開應用程式呈現方式和控管其行為的程式碼。使用 XML 檔案也可以讓您輕鬆為不同的螢幕大小和方向提供不同的版面配置 (詳情請參閱支援不同螢幕大小)。

Android 架構讓您可以靈活運用其中一種或兩種方法,以構建應用程式使用者介面。舉例來說,您可以在 XML 中宣告應用程式的預設版面配置,然後在執行階段修改版面配置。

提示:如要在執行階段偵錯版面配置,請使用版面配置檢查器工具。

寫入 XML

使用 Android 的 XML 詞彙,您就可以利用一系列巢狀元素,快速設計使用者介面版面配置和其中包含的螢幕元素,方法和在 HTML 中建立網頁時一樣。

每個版面配置檔案都只能含有一個根元素 (必須是 View 或 ViewGroup 物件)。定義根元素後,您就可以將其他版面配置物件或小工具新增為子項元素,並逐步定義用於定義版面配置的 View 階層。例如,以下示範如何使用垂直 LinearLayout 以保存 TextViewButton 的 XML 版面配置:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical" >
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
</LinearLayout>

使用 XML 宣告版面配置後,請將檔案儲存到 .xml 擴充功能的 Android 專案的 res/layout/ 目錄中,即可正確編譯。

如要進一步瞭解版面配置 XML 檔案的語法,請參閱版面配置資源文件。

載入 XML 資源

編譯應用程式時,每個 XML 版面配置檔案都會編譯成 View 資源。您必須在 Activity.onCreate() 回呼實作中,從應用程式程式碼載入版面配置資源。方法是呼叫 setContentView(),並採用下列形式將版面配置資源參照傳送至 R.layout.layout_file_name:舉例來說,如果將 XML 版面配置儲存為 main_layout.xml,即可載入該版面配置進行活動,如下所示:

Kotlin

fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}

Java

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

活動啟動時,Android 架構會呼叫活動的 onCreate() 回呼方法 (請參閱活動說明文件中有關生命週期的討論)。

屬性

每個 View 和 ViewGroup 物件都支援各種 XML 屬性。部分屬性是 View 物件特有的屬性 (例如 TextView 支援 textSize 屬性),但這類屬性也被任何可能擴充此類別的 View 物件沿用。有些對於所有 View 物件很常見,因為其是沿用自根 View 類別 (例如 id 屬性)。此外,其他屬性會視為「版面配置參數」;這些屬性會說明 View 物件的特定版面配置方向,並由該物件的父項 ViewGroup 物件定義。

ID

任何 View 物件都有一個相關聯的整數 ID,以識別樹狀子目錄中的 View。應用程式經過編譯時,這個 ID 會參照為整數,但 ID 在版面配置 XML 檔案中通常會以 id 屬性指派為字串。這是所有 View 物件通用的 XML 屬性 (由 View 類別定義),且您會經常使用。XML 標記中 ID 的語法如下:

android:id="@+id/my_button"

位於字串開頭的符號 (@) 表示 XML 剖析器應剖析並展開其他 ID 字串,並將其識別為 ID 資源。加號 (+) 表示必須建立並新增至資源 (位於 R.java 檔案) 中的新資源名稱。Android 架構提供了一些其他 ID 資源。參照 Android 資源 ID 時,您不需要使用加號,但必須新增 android 套件命名空間,如下所示:

android:id="@android:id/empty"

現在 android 套件命名空間已存在,接著就能參照 android.R 資源類別 (而非本機資源類別) 的 ID。

要在應用程式中建立資料檢視並做為參照,常見模式如下:

  1. 在版面配置檔案中定義檢視/小工具並指派專屬 ID:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
    
  2. 然後建立檢視畫面物件的執行個體,並從版面配置擷取 (通常是在 onCreate() 方法中):

    Kotlin

    val myButton: Button = findViewById(R.id.my_button)
    

    Java

    Button myButton = (Button) findViewById(R.id.my_button);
    

建立 RelativeLayout 時,請務必定義檢視畫面物件的 ID。在相對版面配置中,同層級檢視畫面可定義與另一個同層級檢視畫面對應的版面配置,該檢視畫面由專屬 ID 參照。

ID 在整個樹狀結構中不能重複,但應在搜尋樹狀結構中經常出現 (通常是整個樹狀結構,因此盡可能完全不重複)。

注意:在 Android Studio 3.6 以上版本中,檢視繫結功能可以取代 findViewById() 呼叫,並為與檢視互動的程式碼提供編譯時類型安全性。建議您使用檢視繫結,而非 findViewById()

版面配置參數

名為 layout_something 的 XML 版面配置屬性為檢視畫面定義了適合其所在的 ViewGroup 的版面配置參數。

每個 ViewGroup 類別都會導入可擴充 ViewGroup.LayoutParams 的巢狀類別。這個子類別包含定義每個子檢視畫面大小與位置的資源類型,適用於檢視區塊群組。如圖 2 所示,父項檢視區塊群組為每個子項檢視畫面 (包括子項檢視區塊群組) 定義版面配置參數。

圖 2. 以視覺化方式呈現檢視區塊階層,以及與每個檢視畫面相關的版面配置參數

請注意,每個 LayoutParams 子類別對於設定值有自己的語法。每個子項元素都必須定義適用於其父項的 LayoutParams,不過也可能為本身的子項定義不同的 LayoutParams。

所有檢視區塊群組都包含寬度和高度 (layout_widthlayout_height),而且每個檢視畫面都必須定義這些群組。許多 LayoutParam 中也有選用邊界和邊框。

您可以針對確切的測量指定寬度和高度,但您通常不會這麼做。您通常會使用以下常數來設定寬度或高度:

  • wrap_content 會指示您的檢視畫面將自身調整至內容所需的大小。
  • match_parent 可以讓您的檢視畫面佔據父項檢視區塊群組允許的範圍。

一般來說,我們不建議使用絕對單位 (例如像素) 指定版面配置的寬度和高度。相反,我們建議使用相對測量,例如密度獨立像素單位 (dp)、wrap_contentmatch_parent,因為這樣有助於確保可在多種裝置螢幕大小上正確顯示應用程式。可用的測量類型定義於可用的資源文件中。

版面配置位置

檢視畫面的幾何形狀是矩形的。檢視畫面有一個位置 (以一組「左」和「頂端」座標表示) 和兩個維度 (以寬度和高度表示)。位置和維度的單位為像素。

您可以叫用 getLeft()getTop() 方法來擷取檢視畫面的位置。前者會傳回代表檢視畫面的矩形左座標 (或 X)。後者會傳回代表檢視畫面的矩形頂端座標 (或 Y)。這兩種方法都會傳回檢視畫面相對於父項的位置。舉例來說,當 getLeft() 傳回 20 時,表示檢視畫面位於其直接父項左邊緣右側 20 像素處。

此外,我們還提供幾種便利的方法,協助您避免不必要的運算,即 getRight()getBottom()。這些方法會傳回代表檢視畫面矩形的右側邊緣和底部邊緣的座標。舉例來說,呼叫 getRight() 類似於以下運算:getLeft() + getWidth()

大小、邊框間距和邊界

檢視畫面的大小會以寬度和高度表示。檢視畫面確實具備兩組寬度和高度值。

第一組稱為「測量寬度」和「測量高度」。這些維度能定義檢視畫面落在父項之下的大小。您可以呼叫 getMeasuredWidth()getMeasuredHeight() 取得測量的尺寸。

第二個組合又稱為「寬度」和「高度」,有時也稱為「繪製寬度」和「複製高度」。這些維度可定義在螢幕上、繪製時及版面配置後實際畫面的大小。這些值可能與測量的寬度和高度不同 (也可能相同)。呼叫 getWidth()getHeight() 即可取得寬度和高度。

為了評估維度,檢視畫面會考量到邊框間距。邊框間距會以像素的左側、頂端、右側和底部部分顯示 (以像素為單位)。邊框間距可用於將檢視畫面內容以特定像素值偏移。舉例來說,左側邊框間距 2 會將檢視內容推送到左側邊緣右側的 2 像素。您可以使用 setPadding(int, int, int, int) 方法設定邊框,並呼叫 getPaddingLeft()getPaddingTop()getPaddingRight()getPaddingBottom() 進行查詢。

雖然檢視畫面可以定義邊框間距,但並不支援這些邊界。然而,檢視區塊群組會提供這類支援。詳情請參閱 ViewGroupViewGroup.MarginLayoutParams

如要進一步瞭解維度,請參閱維度值一文。

常見版面配置

ViewGroup 類別的每個子類別都提供了特定方式,讓您查看其中的巢狀結構。以下是 Android 平台內建的一些常見的版面配置類型。

注意:雖然您可以在巢狀版面配置中建立一或多個版面配置以完成使用者介面設計,但請盡可能讓版面配置階層保持精簡。如果版面配置的巢狀配置較少 (較寬的檢視區塊階層優於較深的檢視區塊階層),版面配置就會更快繪製。

線性版面配置

將子項版面配置整理成單一水平或垂直列。如果視窗長度超出螢幕長度,則會建立捲軸。

相對版面配置

這項設定可讓您指定子物件相對於彼此 (子項 A 在子項 B 左側) 或相對於父項 (與父項頂端對齊) 的位置。

網頁畫面

顯示網頁。

使用轉接程式建立版面配置

如果版面配置的內容是動態或尚未預先決定,可以使用屬於 AdapterView 的版面配置,在執行階段填入版面配置。AdapterView 類別的子類別使用 Adapter 來將資料繫結至版面配置。Adapter 的功能是資料來源和 AdapterView 版面配置之間的中間人。Adapter 會擷取資料 (來自陣列或資料庫查詢等來源) 並將每個項目轉換為可以添加到 AdapterView 版面配置中的檢視畫面。

由轉接程式支援的常見版面配置包括:

清單檢視

顯示捲動單一欄清單。

格狀檢視

顯示欄和列的捲動網格。

在轉接程式檢視畫面中填入資料

您可以將 AdapterView 執行個體繫結至 Adapter 以填入 ListViewGridViewAdapterView,這樣就能從外部來源擷取資料並建立 View,以代表每個資料項目。

Android 提供 Adapter 的多個子類別,可用於擷取 AdapterView 的各種類型資料及建立檢視畫面。兩種最常見的轉接程式如下:

ArrayAdapter
當資料來源是陣列時,請使用這個轉接程式。根據預設,ArrayAdapter 會為每個項目呼叫 toString() 並將內容放入 TextView,藉此為每個陣列項目建立檢視畫面。

舉例來說,如果您想要在 ListView 中顯示字串陣列,請使用建構函式初始化新的 ArrayAdapter,以指定每個字串和字串陣列的版面配置:

Kotlin

val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)

Java

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, myStringArray);

這個建構函式的引數如下:

  • 您的應用程式 Context
  • 包含陣列中每個字串的 TextView 的版面配置
  • 字串陣列

然後在 ListView 上呼叫 setAdapter()

Kotlin

val listView: ListView = findViewById(R.id.listview)
listView.adapter = adapter

Java

ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);

如要自訂每個項目的外觀,您可以覆寫陣列中物件的 toString() 方法。或者,若要針對 TextView 以外的每個項目建立檢視畫面 (例如,每個陣列項目需要 ImageView),請擴充 ArrayAdapter 類別,然後覆寫 getView() 即可為每個項目傳回您想要的檢視畫面類型。

SimpleCursorAdapter
如果資料來自 Cursor,請使用這個轉接程式。使用 SimpleCursorAdapter 時,您必須針對 Cursor 中的每個列指定要使用的版面配置,以及 Cursor 中的哪些欄應插入版面配置的檢視畫面。舉例來說,假設要建立一份包含使用者名稱和電話號碼的清單,您可以執行一次查詢,該查詢會傳回一個 Cursor,其中包含每個人的列以及名稱和數字的欄。然後建立字串陣列,指定每個結果版面配置中來自 Cursor 的欄,以及指定各欄應放置在對應檢視畫面的整數陣列:

Kotlin

val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME,
                          ContactsContract.CommonDataKinds.Phone.NUMBER)
val toViews = intArrayOf(R.id.display_name, R.id.phone_number)

Java

String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
                        ContactsContract.CommonDataKinds.Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};

SimpleCursorAdapter 執行個體化時,請傳遞每個結果要使用的版面配置、包含結果的 Cursor,以及下列兩個陣列:

Kotlin

val adapter = SimpleCursorAdapter(this,
        R.layout.person_name_and_number, cursor, fromColumns, toViews, 0)
val listView = getListView()
listView.adapter = adapter

Java

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
        R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);

SimpleCursorAdapter 接著會使用提供的版面配置,將各個 fromColumns 項目插入對應的 toViews 檢視畫面,為 Cursor 中的每個列建立檢視畫面。

如要在應用程式的生命週期中,變更轉換程式讀取的基礎資料,請呼叫 notifyDataSetChanged()。系統會通知附加的檢視畫面,指出資料有所變更,且檢視應自行重新整理。

處理點擊事件

您可以導入 AdapterView.OnItemClickListener 介面,回應 AdapterView 中的每個項目的點擊事件。例如:

Kotlin

listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
    // Do something in response to the click
}

Java

// Create a message handling object as an anonymous class.
private OnItemClickListener messageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        // Do something in response to the click
    }
};

listView.setOnItemClickListener(messageClickedHandler);

其他資源

版面配置適用於 Sunflower 試用版應用程式。