Layout a scheda classico ampio con griglia

icona di valutazione a quattro stelle

Le linee guida per la progettazione di app TV definiscono una variante di scheda chiamata Scheda classica ampia, che mostra un'immagine e il relativo blocco di contenuti descrittivi uno accanto all'altro. Quando crei layout bidimensionali complessi per gli schermi TV, l'utilizzo del posizionamento tradizionale basato sulle coordinate o di contenitori Row e Column nidificati in profondità può rendere il codice difficile da leggere, gestire e sottoporre a refactoring. La scheda classica ampia è un caso d'uso ideale per l'API Grid di Jetpack Compose, che ti aiuta a strutturare gli elementi affiancati in modo pulito utilizzando aree di layout 2D semantiche definite dall'utente.

Specifica del componente Scheda classica larga che mostra cinque aree di layout denominate:
      Immagine, Titolo, Sottotitolo, Descrizione e Testo aggiuntivo.
Figura 1. Scheda classica ampia con cinque aree denominate: area dell'immagine e quattro aree di testo nel blocco di contenuti.

Best practice

Implementa il layout della scheda con Grid. L'utilizzo del contenitore Grid migliora la leggibilità del codice separando le dimensioni del layout fisico dal posizionamento degli elementi secondari. Anziché fare affidamento sugli indici delle tracce esatti, definisci le aree semantiche denominate con la funzione area e posiziona i composable secondari con il modificatore gridItem. Combina il dimensionamento flessibile delle tracce, ad esempio GridTrackSize.Auto e minmax(0.dp, 1.fr), con spazi tra le tracce esatti (gap(row = 8.dp, column = 16.dp)) per organizzare in modo chiaro e affidabile i componenti delle schede affiancate complesse.

Ingredienti

  • Grid: un layout di contenitore 2D in Jetpack Compose che dispone i composable secondari in righe e colonne in base a una lambda di configurazione
  • gridItem: un'estensione Modifier che associa un elemento UI secondario a un areaId denominato specifico all'interno di un layout Grid
  • area: una funzione DSL di configurazione all'interno di GridConfigurationScope che mappa un areaId semantico a intervalli o intervalli di righe e colonne specifici
  • Card: un composable di contenitore Material Design che raggruppa elementi UI e stili correlati
  • GridTrackSize.MinMax: una proprietà di dimensionamento delle tracce che definisce i limiti flessibili (min e max) per le dimensioni di righe o colonne
  • GridTrackSize.Auto: una proprietà di dimensionamento delle tracce che dimensiona automaticamente la traccia di riga o colonna in modo che si adatti ai contenuti (column(GridTrackSize.Auto))
  • gap: una funzione di configurazione che specifica la spaziatura verticale (row) e orizzontale (column) tra le tracce della griglia

Passaggi

Definisci gli identificatori delle aree, configura le tracce e le aree della griglia, quindi posiziona i composable secondari.

1. Definisci gli identificatori delle aree semantiche

Innanzitutto, crea una rappresentazione con tipo sicuro delle regioni all'interno del layout della scheda classica ampia. Una classe enum evita errori di battitura delle stringhe e fornisce sicurezza in fase di compilazione quando esegui il mapping delle tracce e posizioni gli elementi secondari.

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

2. Configura le tracce della griglia 2D e le aree denominate

All'interno della lambda config del composable Grid, definisci le colonne e le righe che compongono la struttura della scheda. Utilizza GridTrackSize.Auto per la colonna dell'immagine in modo che il wrapping della larghezza della miniatura sia pulito. Utilizza minmax(0.dp, 1.fr) per la colonna dei contenuti in modo che si espanda in modo flessibile sulla larghezza rimanente della scheda. Specifica la spaziatura delle tracce con gap(row = 8.dp, column = 16.dp). Esegui il mapping degli identificatori CardArea alle relative coordinate delle tracce fisiche utilizzando la funzione area.

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. Posiziona i composable secondari utilizzando il modificatore gridItem

Una volta configurate le tracce e le aree, posiziona ogni elemento UI secondario in base all'intento semantico utilizzando il modificatore gridItem. Puoi dichiarare i composable secondari in qualsiasi ordine. Il contenitore Grid posiziona automaticamente ogni elemento direttamente nella regione 2D assegnata.

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

Risultati

Organizzando la scheda classica ampia con Grid e le aree denominate, ottieni una separazione chiara tra le tracce del layout fisico, le coordinate delle aree e il posizionamento dei composable secondari. Questa struttura rende il layout leggibile e gestibile, rispettando al contempo le linee guida per la progettazione di app TV per i componenti di miniature e descrizioni affiancati.

Risorse aggiuntive