Containerattribute festlegen

Sie können eine Grid-Container-Konfiguration definieren, um flexible Layouts zu erstellen, die auf verschiedene Bildschirmgrößen und Inhaltstypen reagieren. Auf dieser Seite wird Folgendes beschrieben:

Raster definieren

Ein Raster besteht aus Spalten und Zeilen. Das Compose-Element Grid hat einen config-Parameter, der einen Lambda-Ausdruck akzeptiert, um die Spalten und Zeilen innerhalb von GridConfigurationScope zu definieren. Im folgenden Beispiel wird ein Raster mit drei Zeilen und zwei Spalten definiert, die jeweils eine feste Größe haben, die in Dp angegeben ist:

Grid(
    config = {
        repeat(2) {
            column(160.dp)
        }
        repeat(3) {
            row(90.dp)
        }
    }
) {
}

Elemente in einem Raster platzieren

Grid nimmt die UI-Elemente im Lambda-Ausdruck content und platziert sie in Rasterzellen. Das Raster ordnet Elemente unabhängig davon an, ob Sie die Zeilen und Spalten explizit definiert haben. Standardmäßig versucht Grid, ein UI-Element in der verfügbaren Rasterzelle in der Zeile zu platzieren. Wenn das nicht möglich ist, wird es in einer verfügbaren Rasterzelle in der nächsten Zeile platziert. Wenn keine leeren Zellen vorhanden sind, wird mit Grid eine neue Zeile erstellt.

Im folgenden Beispiel hat das Raster sechs Rasterzellen und platziert in jede eine Karte (Abbildung 1). Jede Rasterzelle ist 160dp x 90dp groß, sodass die Gesamtrastergröße 320dp x 270dp beträgt.

Grid(
    config = {
        repeat(2) {
            column(160.dp)
        }
        repeat(3) {
            row(90.dp)
        }
    }
) {
    Card1()
    Card2()
    Card3()
    Card4()
    Card5()
    Card6()
}

Sechs Karten sind in einem Raster mit drei Zeilen und zwei Spalten angeordnet.
Abbildung 1: Sechs Karten sind in einem Raster mit drei Zeilen und zwei Spalten angeordnet.

Wenn Sie dieses Standardverhalten ändern und die Spalten füllen möchten, setzen Sie das Attribut flow auf 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()
}

Mit der Funktion „Fluss“ wird die Richtung geändert, in der Elemente platziert werden.
Abbildung 2: GridFlow.Row (links) und GridFlow.Column (rechts).

Trackgröße verwalten

Zeilen und Spalten werden zusammen als Rasterspur bezeichnet. Sie können die Größe eines Raster-Tracks mit einer der folgenden Methoden angeben:

  • Fest (Dp): Es wird eine bestimmte Größe zugewiesen (z.B. column(180.dp)).
  • Prozentsatz (Float): Weist einen Prozentsatz des insgesamt verfügbaren Speicherplatzes von 0.0f bis 1.0f zu (z.B. row(0.5f) für 50%).
  • Flexibel (Fr): Der verbleibende Platz wird proportional verteilt, nachdem die festen und prozentualen Tracks berechnet wurden. Wenn beispielsweise zwei Zeilen auf 1.fr und 3.fr festgelegt sind, erhält die letztere 75% der verbleibenden Höhe.
  • Intrinsisch: Die Größe des Tracks wird anhand des Inhalts darin festgelegt. Weitere Informationen finden Sie unter Größe von Rasterspuren intrinsisch bestimmen.

Im folgenden Beispiel werden die verschiedenen Optionen für die Spurgröße verwendet, um die Zeilenhöhen zu definieren:

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")

}

Zeilenhöhen, die mit den vier primären Optionen für die Trackgröße definiert wurden.
Abbildung 3: Zeilenhöhen, die mit den vier primären Optionen für die Spurgröße in Grid definiert werden.

Mindestgröße für flexible Rasterspuren festlegen

Wenn ein Grid-Container keinen Platz mehr hat, kann ein standardmäßiger flexibler Track auf 0.dp verkleinert werden. Um dies zu verhindern und dafür zu sorgen, dass Inhalte nicht gestaucht werden, können Sie mit GridTrackSize.MinMax eine explizite Mindestgröße erzwingen und gleichzeitig den Track flexibel halten.

Im folgenden Beispiel wird der ersten Zeile mindestens 100.dp zugewiesen:

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)")
}

Zeilenhöhen, die mit den vier primären Optionen für die Trackgröße definiert wurden.
Abbildung 4: Die erste Zeile hat eine Höhe von mindestens 100.dp.

Mindestgröße für Raster-Tracks festlegen, um Lazy-Listen zu platzieren

Bei flexiblen Standard-Tracks werden automatisch die intrinsischen Größen ihrer untergeordneten Elemente abgefragt, um eine Basisgröße festzulegen. Jetpack Compose lässt jedoch keine Abfrage der intrinsischen Größen von SubcomposeLayout zu, die Komponenten wie LazyColumn und LazyRow unterstützt.

Wenn Sie eine Lazy List in einem standardmäßigen flexiblen Track platzieren, führt dies zu einem IllegalStateException-Absturz. Wenn Sie Lazy-Listen sicher in einem flexiblen Raster-Track platzieren möchten, verwenden Sie MinMax mit einer expliziten Mindestgröße (z. B. 0.dp), um die intrinsische Messung zu umgehen.

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")
        }
    }
}

Zeilenhöhen, die mit den vier primären Optionen für die Trackgröße definiert wurden.
Abbildung 5: LazyColumn in einer Rasterzelle.

Größe des Raster-Tracks intrinsisch bestimmen

Sie können die intrinsische Größenanpassung für ein Grid verwenden, wenn sich das Layout an den Inhalt anpassen soll, anstatt ihn in einen festen Container zu zwingen. Die Größe der Rasterspur wird mit den folgenden Werten bestimmt:

  • GridTrackSize.MaxContent: Die maximale intrinsische Größe des Inhalts wird verwendet (z.B. wird die Breite durch die volle Länge des Textes in einem Textblock ohne Umbruch bestimmt).
  • GridTrackSize.MinContent: Die minimale intrinsische Größe des Inhalts wird verwendet (z.B. wird die Breite durch das längste einzelne Wort in einem Textblock bestimmt).
  • GridTrackSize.Auto: Verwenden Sie eine flexible Größe für einen Track, die sich an den verfügbaren Platz anpasst. Es verhält sich standardmäßig wie MaxContent, verkleinert und bricht den Inhalt jedoch um, damit er in den übergeordneten Container passt.

Im folgenden Beispiel werden zwei Texte nebeneinander platziert. Die Spaltengröße für den ersten Text wird durch die erforderliche Mindestbreite für die Anzeige des Texts bestimmt. Die Breite der zweiten Spalte hängt von der erforderlichen maximalen Breite des Texts ab.

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.")
}

In den Spalten angegebene intrinsische Größen.
Abbildung 5: In den Spalten angegebene intrinsische Größen.

Abstände zwischen Zeilen und Spalten festlegen

Nachdem Sie die Größe der Rasterspuren festgelegt haben, können Sie den Rasterabstand ändern, um den Abstand zwischen den Spuren anzupassen. Sie können den Spaltenabstand mit der Funktion columnGap und den Zeilenabstand mit rowGap angeben. Im folgenden Beispiel gibt es zwischen den Zeilen einen Abstand von 16dp und zwischen den Spalten einen Abstand von 8dp (Abbildung 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()
}

Lücken zwischen Zeilen und Spalten.
Abbildung 6: Lücken zwischen Zeilen und Spalten.

Sie können auch die praktische Funktion gap verwenden, um Abstände mit derselben Spalten- und Zeilengröße zu definieren und Spalten- und Abstandgrößen separat mit einer einzigen Funktion zu definieren. Mit dem folgenden Code werden dem Raster 8dp-Lücken hinzugefügt:

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()
}

Rasterbereiche mit benannten Bereichen definieren

Mit benannten Bereichen können Sie Gruppen von Rasterzellen, die als Rasterbereiche bezeichnet werden, Namen zuweisen. Sie können diese Namen anstelle von Koordinatenindexen verwenden, wenn Sie UI-Elemente im Raster platzieren.

Die Verwendung benannter Bereiche hat zwei wesentliche Vorteile für die Lesbarkeit des Codes:

  • Beim Definieren des Rasterlayouts sind der Zweck und die Platzierung des erwarteten Inhalts klar.
  • Der Zweck der Inhalte ist klar erkennbar.

Um komplexe Layouts übersichtlich zu gestalten, können Sie die physische Rasterstruktur von der Platzierung untergeordneter Elemente entkoppeln, indem Sie semantische Rasterbereiche definieren.

Verwenden Sie im Lambda config die Funktion area in GridConfigurationScope, um benannte Bereiche im Raster zu registrieren. Anschließend können Sie diesen Bereichen untergeordnete Composables zuweisen. Verwenden Sie dazu den Modifikator gridItem mit der entsprechenden Bereichskennung. Die Funktion area ordnet eine semantische Kennung (z. B. einen enum-Klassenwert oder einen Stringschlüssel) einer Reihe von physischen Rasterkoordinaten zu. Rasterlinien und Indexe sind 1-basiert (d. h., die erste Zeile ist 1 und die erste Spalte ist 1).

Sie definieren beispielsweise ein Raster mit vier Bereichs-IDs:

/**
 * An enum representing the IDs for named areas within the grid.
 */
enum class GridAreaNames {
    Area1,
    Area2,
    Area3,
    Area4
}

Geben Sie den Namen des Bereichs mit dem Parameter areaId sowie die Zellenkoordinaten und -spannen des Bereichs an. Der Modifikator gridItem verwendet areaId als Schlüssel, um jedes untergeordnete Element dem vorgesehenen Rasterbereich zuzuweisen, wie im folgenden Beispiel gezeigt:

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)
    )
}

Mit benannten Bereichen kannst du das physische Layout-Raster (z. B. Zeilen, Spalten oder Trackgrößen) im Lambda-Ausdruck config neu organisieren oder anpassen, ohne die Reihenfolge oder Parameter der untergeordneten Composables ändern zu müssen.