Grid コンテナ構成を定義して、さまざまな画面サイズやコンテンツ タイプに対応する柔軟なレイアウトを作成できます。このページでは、次の操作を行う方法について説明します。
- グリッドを定義する: 行と列の基本構造を設定します。
- アイテムをグリッドに配置する: アイテムをグリッドセルに配置する方法と、フローの方向を変更する方法を理解します。
- トラックのサイズを管理する: 固定サイズ、パーセント サイズ、フレキシブル サイズ、イントリンシック サイズを使用して、トラックのサイズを設定します。
- ギャップを設定する: 行と列の間の「ガター」を管理します。
グリッドを定義する
グリッドは列と行で構成されます。Grid コンポーザブルには、GridConfigurationScope 内の列と行を定義するラムダを受け入れる config パラメータがあります。次の例では、3 行 2 列のグリッドを定義しています。各行と各列のサイズは Dp で指定された固定サイズです。
Grid( config = { repeat(2) { column(160.dp) } repeat(3) { row(90.dp) } } ) { }
アイテムをグリッドに配置する
Grid は、content ラムダの UI 要素を取得し、グリッドセルに配置します。グリッドは、行と列を明示的に定義しているかどうかに関係なく、アイテムをレイアウトします。デフォルトでは、Grid は行内の使用可能なグリッドセルに UI 要素を配置しようとします。それができない場合は、次の行の使用可能なグリッドセルに配置します。空のセルがない場合、Grid は新しい行を作成します。
次の例では、グリッドに 6 つのグリッドセルがあり、それぞれにカードが配置されています(図 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に割り当てます(例: 50% の場合はrow(0.5f))。 - フレキシブル(
Fr): 固定トラックとパーセンテージ トラックが計算された後、残りのスペースを比例配分します。たとえば、2 つの行が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 の 4 つの主要なトラックサイズ オプションを使用して定義された行の高さ。
フレキシブル グリッド トラックの最小サイズを設定する
グリッド コンテナに空きスペースがない場合、標準のフレキシブル トラックは 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 以上です。
遅延リストを配置する最小グリッド トラックサイズを設定する
標準のフレキシブル トラックは、子の固有サイズを自動的にクエリして、ベースサイズを確立します。ただし、Jetpack Compose では、LazyColumn や LazyRow などのコンポーネントをサポートする SubcomposeLayout の固有サイズをクエリすることはできません。
標準のフレキシブル トラック内に遅延リストを配置すると、IllegalStateException クラッシュが発生します。フレキシブル グリッド トラック内に遅延リストを安全に配置するには、明示的な最小サイズ(0.dp など)を指定した MinMax を使用して、固有の測定パスをバイパスします。
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のように動作しますが、コンテンツを縮小してラップし、親コンテナ内に収まるようにします。
次の例では、2 つのテキストを並べて配置しています。 最初のテキストの列サイズは、テキストを表示するために必要な最小幅によって決まり、2 番目の列幅は、テキストに必要な最大幅によって決まります。
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 を使用して、同じ列サイズと行サイズのギャップを定義したり、1 つの関数を使用して列サイズとギャップサイズを個別に定義したりすることもできます。次のコードは、グリッドに 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 要素を配置するときに、座標インデックスの代わりにこれらの名前を使用できます。
名前付きエリアを使用すると、コードの読みやすさに主に 2 つのメリットがあります。
- グリッド レイアウトを定義する際、想定されるコンテンツの目的と配置が明確である。
- コンテンツを追加する際、そのコンテンツの目的が明確である。
複雑なレイアウトを明確に整理するには、セマンティック グリッド領域を定義して、物理グリッド構造を子配置から切り離します。
config ラムダ内で、GridConfigurationScope の area 関数を使用して、グリッド内の名前付きエリアを登録します。その後、対応するエリア識別子を指定した gridItem 修飾子を使用して、子コンポーザブルをこれらのエリアに割り当てることができます。area 関数は、セマンティック識別子(enum クラス値や文字列キーなど)を物理グリッド座標のセットにマッピングします。グリッド線とインデックスは 1 ベースです(つまり、最初の行は 1、最初の列は 1 です)。
たとえば、4 つのエリア 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 ラムダで物理レイアウト グリッドを再編成または調整(行、列、トラックサイズの変更など)できます。