您可以定義 Grid 容器設定,建立可因應不同螢幕大小和內容類型的彈性版面配置。本頁面說明如何執行下列操作:
- 定義格線:設定資料列和資料欄的基本結構。
- 在格線中放置項目:瞭解如何將項目放入格線儲存格,以及如何變更流程方向。
- 管理軌道大小:使用固定、百分比、彈性和內建大小設定軌道大小。
- 設定間隔:管理列與欄之間的「間隔」。
定義格線
格線由欄和列組成。Grid 可組合函式具有 config 參數,可接受 lambda 定義 GridConfigurationScope 中的資料欄和資料列。以下範例定義了具有三列兩欄的格線,每列/欄都有 Dp 指定的固定大小:
Grid( config = { repeat(2) { column(160.dp) } repeat(3) { row(90.dp) } } ) { }
以格狀排列項目
Grid 會擷取 content lambda 中的 UI 元素,並放入格線儲存格。無論是否明確定義列和欄,格線都會排列項目。根據預設,Grid 會嘗試將 UI 元素放在該列中可用的格狀儲存格;如果無法,則會將其放在下一列中可用的格狀儲存格。如果沒有空白儲存格,Grid 會建立新資料列。
在以下範例中,格線有六個格線儲存格,並在每個儲存格中放置一張資訊卡 (圖 1)。每個格線儲存格的大小為 160dp x 90dp,因此格線總大小為 320dp x 270dp。
Grid( config = { repeat(2) { column(160.dp) } repeat(3) { row(90.dp) } } ) { Card1() Card2() Card3() Card4() Card5() Card6() }
如要將這項預設行為變更為依資料欄填入,請將 flow 屬性設為 GridFlow.Column。
Grid( config = { repeat(2) { column(160.dp) } repeat(3) { row(90.dp) } gap(8.dp) flow = GridFlow.Column // Grid tries to place items to fill the column }, ) { Card1() Card2() Card3() Card4() Card5() Card6() }
GridFlow.Row (左) 和 GridFlow.Column (右)。
管理軌道大小
列和欄統稱為「格線軌跡」。您可以使用下列任一方法指定格線軌道的大小:
- 固定 (
Dp):分配特定大小 (例如column(180.dp))。 - 百分比 (
Float):分配0.0f到1.0f之間可用空間總量的百分比 (例如row(0.5f)代表 50%)。 - 彈性 (
Fr):計算固定和百分比軌道後,按比例分配剩餘空間。舉例來說,如果將兩個資料列設為1.fr和3.fr,後者會獲得剩餘高度的 75%。 - Intrinsic:根據內容大小調整軌道。詳情請參閱「從本質上決定格線軌跡大小」。
以下範例使用不同的軌道大小選項定義列高:
Grid( config = { column(1f) row(100.dp) row(0.2f) row(1.fr) row(GridTrackSize.Auto) }, modifier = Modifier.height(480.dp) ) { PastelRedCard("Fixed(100.dp)") PastelGreenCard("Percentage(0.2f)") PastelBlueCard("Flex(1.fr)") PastelYellowCard("Auto") }
Grid 中的四個主要軌道大小調整選項定義的列高。設定彈性網格軌道的最小大小
當網格容器沒有剩餘空間時,標準彈性軌道可以縮小至 0.dp。為避免這種情況,並確保內容不會被擠壓,請使用 GridTrackSize.MinMax 強制設定明確的最小尺寸,同時保持軌道彈性。
以下範例會為第一列分配至少 100.dp:
Grid( config = { column(1f) // The first row has a minimum height of 100.dp and can expand to // the half of the remaining space. row(GridTrackSize.MinMax(100.dp, 1.fr)) // The second row takes the half of the remaining space. row(1.fr) // The third row has a fixed height of 200.dp. row(200.dp) }, modifier = Modifier.size(360.dp) // Total grid height is 360.dp ) { PastelRedCard("MinMax(100.dp, 1.fr)") PastelGreenCard("Flex(1.fr)") PastelBlueCard("Fixed(200.dp)") }
100.dp。
設定格線軌道大小下限,以便放置 Lazy 清單
標準彈性軌道會自動查詢子項的內建大小,以建立基本大小。不過,Jetpack Compose 禁止查詢 SubcomposeLayout 的固有大小,這會支援 LazyColumn 和 LazyRow 等元件。
將 Lazy 清單放在標準彈性軌道中,會導致 IllegalStateException 異常終止。如要安全地將 Lazy 清單放入彈性網格軌道,請使用 MinMax 並明確指定大小下限 (例如 0.dp),略過內建測量階段。
Grid( config = { column(1f) // The first row's height is determined by the height of the Text composable. row(GridTrackSize.Auto) // The second row occupies the remaining space, allowing the LazyColumn to scroll. row(GridTrackSize.MinMax(0.dp, 1.fr)) gap(8.dp) }, modifier = Modifier.size(width = 170.dp, height = 240.dp) ) { Text("LazyColumn in a Grid") // The LazyColumn is placed in the second row, filling the remaining space. LazyColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) { items(100) { number -> PastelGreenCard("Card $number") } } }
LazyColumn 位於格狀空間的儲存格中。
從本質上決定格線軌道大小
如果您希望版面配置能配合內容調整,而不是強制放入固定容器,可以對 Grid 使用內建大小。格線軌道大小取決於下列值:
GridTrackSize.MaxContent:使用內容的最大固有大小 (例如,寬度取決於文字區塊中未換行的文字全長)。GridTrackSize.MinContent:使用內容的最小固有大小 (例如,寬度取決於文字區塊中最長的單字)。GridTrackSize.Auto:為軌道使用彈性大小,根據可用空間調整。根據預設,其行為與MaxContent類似,但會縮小並包裝內容,以符合父項容器。
以下範例會並排顯示兩個文字。第一個文字的欄大小取決於顯示文字所需的最小寬度,第二個欄寬度則取決於文字所需的最大寬度。
Grid( config = { column(GridTrackSize.MinContent) column(GridTrackSize.MaxContent) row(1.0f) }, modifier = Modifier.width(480.dp) ) { Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras imperdiet.") Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras imperdiet.") }
設定列與欄之間的間距
調整網格軌道大小後,您可以修改網格間隙,調整軌道之間的間距。您可以使用 columnGap 函式指定欄間距,並使用 rowGap 指定列間距。在以下範例中,每列之間有 16dp 的間距,每欄之間有 8dp 的間距 (圖 5)。
Grid( config = { repeat(2) { column(160.dp) } repeat(3) { row(90.dp) } rowGap(16.dp) columnGap(8.dp) } ) { Card1() Card2() Card3() Card4() Card5() Card6() }
您也可以使用便利函式 gap 定義相同欄和列大小的間隔,並使用單一函式分別定義欄和間隔大小。以下程式碼會在格線中加入 8dp 間距:
Grid( config = { repeat(2) { column(160.dp) } repeat(3) { row(90.dp) } gap(8.dp) // Equivalent to columnGap(8.dp) and rowGap(8.dp) } ) { Card1() Card2() Card3() Card4() Card5() Card6() }
使用已命名區域定義格線區域
命名區域可讓您為一組網格儲存格附加名稱,稱為「網格區域」。在格線中放置 UI 元素時,您可以使用這些名稱,而非座標索引。
使用命名區域對程式碼可讀性有兩大好處:
- 定義格線版面配置時,預期內容的目的和位置應明確。
- 新增內容時,該內容的目的明確。
如要清楚整理複雜的版面配置,您可以定義語意格線區域,將實體格線結構與子項位置分離。
在 config lambda 中,使用 GridConfigurationScope 中的 area 函式,在格線中註冊已命名的區域。接著,您可以使用 gridItem 修飾符和對應的區域 ID,將子可組合項指派給這些區域。area 函式會將語意 ID (例如 enum 類別值或字串鍵) 對應至一組實體格線座標。格線和索引從 1 開始 (也就是說,第一列是 1,第一欄是 1)。
舉例來說,您定義了包含四個區域 ID 的格線:
/** * An enum representing the IDs for named areas within the grid. */ enum class GridAreaNames { Area1, Area2, Area3, Area4 }
使用 areaId 參數提供區域名稱,以及區域的儲存格座標和跨距。gridItem 修飾符會使用 areaId 做為索引鍵,將每個子項項目指派至指定的格線區域,如以下範例所示:
Grid( config = { // Define a single column that takes all available width. repeat(2) { column(0.5f) } // Define four rows, each taking 25% of the total height. repeat(4) { row(0.25f) } // Define named grid areas by associating an areaId with specific row and column indices. // Row and column indices are 1-based. area(areaId = GridAreaNames.Area1, row = 1, column = 1, columnSpan = 2) area(areaId = GridAreaNames.Area2, row = 2, column = 1, rowSpan = 3) area(areaId = GridAreaNames.Area3, rows = 2..3, columns = 2..2) area(areaId = GridAreaNames.Area4, row = 4, column = 2) gap(4.dp) }, modifier = Modifier.size(360.dp) ) { PastelRedCard( "Area 1", // Use Modifier.gridItem(areaId) to place this composable into the // grid area defined with the matching ID in the config block. modifier = Modifier.gridItem(areaId = GridAreaNames.Area1) ) PastelGreenCard( "Area 2", modifier = Modifier.gridItem(areaId = GridAreaNames.Area2) ) PastelBlueCard( "Area 3", modifier = Modifier.gridItem(areaId = GridAreaNames.Area3) ) PastelYellowCard( "Area 4", modifier = Modifier.gridItem(areaId = GridAreaNames.Area4) ) }
使用命名區域,您可以在 config lambda 中重新組織或調整實體版面配置格線 (例如變更列、欄或軌道大小),而不必修改子項可組合項的順序或參數。