Breites klassisches Kartenlayout mit Raster

Symbol für Bewertung mit vier Sternen

In den Designrichtlinien für TV-Apps wird eine Kartenvariante namens „Breite klassische Karte“, definiert, bei der ein Bild und der zugehörige beschreibende Inhaltsblock nebeneinander angezeigt werden. Beim Erstellen komplexer zweidimensionaler Layouts für TV-Bildschirme kann die Verwendung der herkömmlichen koordinatenbasierten Positionierung oder tief verschachtelter Row- und Column-Container dazu führen, dass der Code schwer zu lesen, zu verwalten und umzugestalten ist. Die breite klassische Karte ist ein idealer Anwendungsfall für die Jetpack Compose Grid-API, mit der Sie nebeneinander angeordnete Elemente mithilfe semantischer, benutzerdefinierter 2D-Layoutbereiche sauber strukturieren können.

Spezifikation der Komponente „Breite klassische Karte“ mit fünf benannten Layoutbereichen: Bild, Titel, Untertitel, Beschreibung und zusätzlicher Text.
Abbildung 1. Breite klassische Karte mit fünf benannten Bereichen: Bildbereich und vier Textbereiche im Inhaltsblock.

Best Practices

Implementieren Sie das Kartenlayout mit Grid. Durch die Verwendung des Grid-Containers wird die Lesbarkeit des Codes verbessert, da die physischen Layoutabmessungen von der Platzierung der untergeordneten Elemente entkoppelt werden. Anstatt sich auf genaue Track-Indizes zu verlassen, definieren Sie semantische benannte Bereiche mit der Funktion area und platzieren Sie untergeordnete Composables mit dem Modifikator gridItem. Kombinieren Sie flexible Track-Größen, z. B. GridTrackSize.Auto und minmax(0.dp, 1.fr), mit genauen Track-Abständen (gap(row = 8.dp, column = 16.dp)) um komplexe nebeneinander angeordnete Kartenkomponenten klar und robust zu organisieren.

Zutaten

  • Grid: Ein 2D-Containerlayout in Jetpack Compose, das untergeordnete Composables basierend auf einem Konfigurations-Lambda in Zeilen und Spalten anordnet
  • gridItem: Eine Modifier-Erweiterung, die ein untergeordnetes UI-Element mit einer bestimmten benannten areaId in einem Grid-Layout verknüpft
  • area: Eine Konfigurations-DSL-Funktion in GridConfigurationScope, die eine semantische areaId bestimmten Zeilen- und Spaltenbereichen zuordnet
  • Card: Ein Material Design-Container-Composable, das zugehörige UI-Elemente und -Stile gruppiert
  • GridTrackSize.MinMax: Eine Eigenschaft zur Track-Größenanpassung, mit der flexible Grenzen (min und max) für Zeilen- oder Spaltendimensionen definiert werden
  • GridTrackSize.Auto: Eine Eigenschaft zur Track-Größenanpassung, mit der die Zeilen- oder Spalten spur automatisch an den Inhalt angepasst wird (column(GridTrackSize.Auto))
  • gap: Eine Konfigurationsfunktion, mit der der vertikale (row) und horizontale (column) Abstand zwischen den Grid-Tracks angegeben wird

Schritte

Definieren Sie Bereichs-IDs, konfigurieren Sie die Grid-Tracks und -Bereiche und platzieren Sie dann die untergeordneten Composables.

1. Semantische Bereichs-IDs definieren

Erstellen Sie zuerst eine typsichere Darstellung der Bereiche in Ihrem Layout für die breite klassische Karte. Eine enum-Klasse vermeidet Tippfehler in Strings und bietet Kompilierzeitsicherheit beim Zuordnen von Tracks und Platzieren von untergeordneten Elementen.

enum class CardArea {
    Image,
    Title,
    Subtitle,
    Description,
    ExtraText,
}

2. 2D-Grid-Tracks und benannte Bereiche konfigurieren

Definieren Sie im config-Lambda Ihres Grid-Composables die Spalten und Zeilen, aus denen die Kartenstruktur besteht. Verwenden Sie GridTrackSize.Auto für die Bildspalte, damit die Breite des Thumbnails sauber umbrochen wird. Verwenden Sie minmax(0.dp, 1.fr) für die Inhaltsspalte, damit sie sich flexibel über die verbleibende Kartenbreite erstreckt. Geben Sie den Track-Abstand mit gap(row = 8.dp, column = 16.dp) an. Ordnen Sie Ihre CardArea-IDs mit der Funktion area den physischen Track-Koordinaten zu.

Grid(
    config = {
        // Define columns: left column for image, right for content
        column(GridTrackSize.Auto)
        column(minmax(0.dp, 1.fr))

        // Define row tracks for the vertical content stack
        row(GridTrackSize.Auto)
        row(GridTrackSize.Auto)
        row(GridTrackSize.Auto)
        row(GridTrackSize.Auto)

        // Map semantic identifiers to grid coordinates and spans
        area(CardArea.Image, row = 1, column = 1, rowSpan = 4)
        area(CardArea.Title, row = 1, column = 2)
        area(CardArea.Subtitle, row = 2, column = 2)
        area(CardArea.Description, row = 3, column = 2)
        area(CardArea.ExtraText, row = 4, column = 2)

        gap(row = 8.dp, column = 16.dp)
    }
) {
    // Child elements placed in Step 3
}

3. Untergeordnete Composables mit dem Modifikator „gridItem“ platzieren

Nachdem Sie die Tracks und Bereiche konfiguriert haben, platzieren Sie jedes untergeordnete UI-Element rein nach semantischer Absicht mit dem Modifikator gridItem. Sie können untergeordnete Composables in beliebiger Reihenfolge deklarieren. Der Grid-Container positioniert jedes Element automatisch direkt in seinem zugewiesenen 2D-Bereich.

@Composable
fun WideClassicCard(
    imageContent: @Composable () -> Unit,
    title: String,
    subtitle: String,
    description: String,
    extraText: String,
    modifier: Modifier = Modifier,
) {
    Card(modifier = modifier) {
        Grid(
            config = {
                // Define columns: left column for image, right for content
                column(GridTrackSize.Auto)
                column(minmax(0.dp, 1.fr))

                // Define row tracks for the vertical content stack
                row(GridTrackSize.Auto)
                row(GridTrackSize.Auto)
                row(GridTrackSize.Auto)
                row(GridTrackSize.Auto)

                // Map semantic identifiers to grid coordinates and spans
                area(CardArea.Image, row = 1, column = 1, rowSpan = 4)
                area(CardArea.Title, row = 1, column = 2)
                area(CardArea.Subtitle, row = 2, column = 2)
                area(CardArea.Description, row = 3, column = 2)
                area(CardArea.ExtraText, row = 4, column = 2)

                gap(row = 8.dp, column = 16.dp)
            },
        ) {
            Box(modifier = Modifier.gridItem(CardArea.Image)) {
                imageContent()
            }
            Text(
                text = title,
                style = MaterialTheme.typography.titleLarge,
                modifier = Modifier
                    .gridItem(CardArea.Title)
                    .padding(top = 16.dp, end = 16.dp),
            )

            Text(
                text = subtitle,
                style = MaterialTheme.typography.titleMedium,
                modifier = Modifier
                    .gridItem(CardArea.Subtitle)
                    .padding(end = 16.dp),
            )

            Text(
                text = description,
                style = MaterialTheme.typography.bodyMedium,
                modifier = Modifier
                    .gridItem(CardArea.Description)
                    .padding(end = 16.dp),
            )

            Text(
                text = extraText,
                style = MaterialTheme.typography.labelSmall,
                modifier = Modifier
                    .gridItem(CardArea.ExtraText)
                    .padding(bottom = 16.dp, end = 16.dp),
            )
        }
    }
}

Ergebnisse

Wenn Sie Ihre breite klassische Karte mit Grid und benannten Bereichen organisieren, erreichen Sie eine saubere Trennung zwischen physischen Layout-Tracks, Bereichskoordinaten und der Platzierung untergeordneter Composables. Diese Struktur macht Ihr Layout lesbar und wartbar und entspricht gleichzeitig den Designrichtlinien für TV-Apps für nebeneinander angeordnete Thumbnail- und Beschreibungskomponenten.

Zusätzliche Ressourcen