Compose 版面配置基本須知

Jetpack Compose 可讓您更加輕鬆地設計和建構應用程式的使用者介面。Compose 透過下列方法將狀態轉換為 UI 元素:

  1. 元素組合
  2. 元素版面配置
  3. 元素繪圖

Compose 透過組合、版面配置和繪圖將狀態轉換為 UI

本文件的重點在於元素的版面配置,說明 Compose 提供的一些建構元素,幫助您配置 UI 元素。

Compose 的版面配置目標

版面配置系統的 Jetpack Compose 實作主要有兩個目標:

可組合函式的基本概念

可組合函式是 Compose 的基本建構元素。可組合函式是會發出 Unit 的函式,用於說明您使用者介面的某些部分。函式會接收部分輸入內容,然後產生螢幕上顯示的內容。如要瞭解更多有關可組合元件的資訊,請參閱 Compose 心理模型說明文件。

可組合函式可能會發出多個 UI 元素。不過,如果您未提供如何排列這些元素的指導方式,Compose 可能會以您不喜好的方式排列元素。例如,下列程式碼會產生兩個文字元素:

@Composable
fun ArtistCard() {
    Text("Alfred Sisley")
    Text("3 minutes ago")
}

如果沒有提供您希望如何排列它們的指導方式,Compose 會將文字元素彼此堆疊在一起,這使得文字元素不容易讀取:

兩個文字元素彼此重疊,使得文字不容易讀取

Compose 提供一系列可立即使用的版面配置,協助您排列 UI 元素,並輕鬆定義專屬您個人、更加專業的版面配置。

標準版面配置元件

在許多情況下,您都可以使用 Compose 的標準版面配置元素

使用 Column 將項目垂直地放置在螢幕上。

@Composable
fun ArtistCard() {
    Column {
        Text("Alfred Sisley")
        Text("3 minutes ago")
    }
}

兩個文字元素以資料欄版面配置排列,因此文字清楚易讀

同樣地,使用 Row 將項目水平地放置在螢幕上。ColumnRow 都支援設定它們所包含的元素對齊方式。

@Composable
fun ArtistCard(artist: Artist) {
    Row(verticalAlignment = Alignment.CenterVertically) {
        Image(/*...*/)
        Column {
            Text(artist.name)
            Text(artist.lastSeenOnline)
        }
    }
}

顯示較複雜的版面配置,在文字元素欄旁顯示小圖形

使用 Box 即可將元素置於另一個元素的上方。Box 也支援設定其所包含的元素的具體對齊方式。

@Composable
fun ArtistAvatar(artist: Artist) {
    Box {
        Image(/*...*/)
        Icon(/*...*/)
    }
}

顯示兩個彼此堆疊的元素

通常只需要這些建構元素即可。您可以編寫自己的可組合函式,將這些版面配置合併成更適合的版面配置,以搭配您的應用程式。

比較三個簡單的版面配置可組合函式:欄、列和方塊

若要在 Row 中設定子項位置,請設定 horizontalArrangementverticalAlignment 引數。針對 Column,設定 verticalArrangementhorizontalAlignment 引數:

@Composable
fun ArtistCard(artist: Artist) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.End
    ) {
        Image(/*...*/)
        Column { /*...*/ }
    }
}

項目會靠右對齊

版面配置型式

在版面配置型式中,UI 樹狀結構是以單一傳遞方式進行配置。系統會要求每個節點先自行測量,接著以遞迴方式測量任何子項,將大小限制傳遞至樹狀結構下方的子項。接下來,系統會設定分葉節點的大小和位置,並將已解析的大小和位置指示傳遞回樹狀結構上方。

簡單地說,父項測量會在子項測量之前,但是尺寸與位置的設定是在子項之後。

請考慮使用下列 SearchResult 函式。

@Composable
fun SearchResult(...) {
  Row(...) {
    Image(...)
    Column(...) {
      Text(...)
      Text(..)
    }
  }
}

此函式會產生以下 UI 樹狀結構,

SearchResult
  Row
    Image
    Column
      Text
      Text

SearchResult 範例中,UI 樹狀結構的版面配置會依照以下順序:

  1. 系統會要求根節點 Row 進行測量。
  2. 根節點 Row 會要求第一個子項 Image 進行測量。
  3. Image 是分葉節點 (也就是沒有任何子項),因此會報告大小並傳回位置指示。
  4. 根節點 Row 會要求第二個子項 Column 進行測量。
  5. Column 節點會要求其第一個 Text 子項進行測量。
  6. 第一個 Text 節點是分葉節點,因此會報告大小並傳回位置指示。
  7. Column 節點會要求其第二個 Text 子項進行測量。
  8. 第二個 Text 節點是分葉節點,因此會報告大小並傳回位置指示。
  9. 既然已經測量 Column 節點、設定其子項大小與位置,因此它可以決定自己的大小和位置。
  10. 既然已經測量根節點 Row、設定其子項大小與位置,因此它可以決定自己的大小和位置。

在搜尋結果 UI 樹狀結構中的測量、大小與位置順序

效能

Compose 僅會測量子項一次,藉此達到高度效能。單一行程 測量功能非常適合效能,可讓 Compose 有效率地處理深度 UI 樹狀結構。如果某個元素測量其子項兩次,而該子項又測量其每個子項兩次 (以此類推),那麼每次嘗試配置整個 UI 都需要花費許多工作,進而難以掌握應用程式效能。

如果版面配置因為某些原因需要多次測量,Compose 會提供特殊系統,也就是內建函式測量。如要閱讀更多有關此功能的資訊,請參閱 Compose 版面配置中的內建函式測量

由於測量和位置是版面配置傳遞的明顯子階段,因此僅會影響項目位置 (而不是測量) 的任何變更都會個別執行。

在版面配置中使用輔助鍵

如同 Compose 輔助鍵中所述,您可以使用輔助鍵來裝飾或增加可組合元件。輔助鍵是自訂版面配置時所不可少的。舉例來說,我們會鏈結數個輔助鍵以自訂 ArtistCard

@Composable
fun ArtistCard(
    artist: Artist,
    onClick: () -> Unit
) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ }
        Spacer(Modifier.size(padding))
        Card(elevation = 4.dp) { /*...*/ }
    }
}

較複雜的版面配置,使用輔助鍵來改變圖形的排列方式,以及回應使用者輸入內容的區域

在上面的程式碼中,注意共同使用的不同輔助鍵函式。

  • clickable 可對於使用者輸入內容產生可組合回應,並顯示漣漪。
  • padding 會在元素周圍放置空格。
  • fillMaxWidth 提供可組合元件填入透過父項提供的寬度上限。
  • size() 會指定元素的偏好寬度和高度。

可捲動的版面配置

如需瞭解更多有關可捲動版面配置的資訊,請參閱 Compose 手勢說明文件

如需關於清單和惰性清單的資訊,請參閱 Compose 清單說明文件

回應式版面配置

版面配置在設計時應考量不同的螢幕方向和板型規格大小。Compose 提供一些現成的機制, 可協助您配合各種螢幕設定調整可組合的版面配置。

限制

為了瞭解父項的限制,並據此設計版面配置,您可以使用 BoxWithConstraints測量限制位於內容 lambda 的範圍內。您可以使用這些測量限制,針對不同的螢幕設定撰寫不同的版面配置:

@Composable
fun WithConstraintsComposable() {
    BoxWithConstraints {
        Text("My minHeight is $minHeight while my maxWidth is $maxWidth")
    }
}

基於位置的版面配置

Compose 提供許多根據質感設計建立,並且包含 androidx.compose.material:material 依附元件的可組合元件 (在 Android Studio 中建立 Compose 專案時已包括),可讓您輕鬆地建立 UI。例如 DrawerFloatingActionButtonTopAppBar 之類的元素也皆有提供。

材質元件會大量使用位置 API,Compose 會採用這個模式將自訂層帶入可組合元件的頂端。這種方法使得元件更具彈性,因為元件接受的是可自行設定的子項元素,而不需要揭露子項的所有設定參數。位置會在 UI 中保留空白,讓開發人員依據需要填入。舉例來說,您可以在 TopAppBar 中自訂下列位置:

顯示材質元件應用程式列中可用位置的圖表

可組合元件通常採用 content 可組合的 lambda ( content: @Composable () -> Unit)。位置 API 會公開特定用途的多個 content 參數。舉例來說,TopAppBar 可讓您提供 titlenavigationIconactions 的內容。

舉例來說, Scaffold 可讓您使用基本的質感設計版面配置結構來實作使用者介面。 Scaffold 為最常用頂層材質元件提供位置, 例如 TopAppBarBottomAppBarFloatingActionButtonDrawer。藉由使用 Scaffold,即可輕鬆確保這些元件的位置正確 並且正常運作。

JetNews 範例應用程式使用 Scaffold 來定位多個元素

@Composable
fun HomeScreen(/*...*/) {
    Scaffold(
        drawerContent = { /*...*/ },
        topBar = { /*...*/ },
        content = { /*...*/ }
    )
}