Modelli di sezioni

Questo documento fornisce dettagli su come utilizzare gli strumenti per la creazione di modelli in Android Jetpack per creare le Sezioni.

Definisci il modello Sezione

Le sezioni vengono create utilizzando un ListBuilder. ListBuilder consente di aggiungere diversi tipi di righe che vengono visualizzate in un elenco. Questa sezione descrive ciascuno di questi tipi di riga e come vengono costruiti.

Azione Slice

L'elemento più basilare di un modello Sezione è SliceAction. Un elemento SliceAction contiene un'etichetta insieme a PendingIntent ed è uno dei seguenti:

  • Pulsante icona
  • Opzione di attivazione/disattivazione predefinita
  • Pulsante di attivazione/disattivazione personalizzato (disegnabile con stato on/off)

SliceAction viene utilizzato dagli strumenti per la creazione dei modelli descritti nel resto di questa sezione. In un elemento SliceAction è possibile definire una modalità immagine che determina il modo in cui viene presentata l'immagine per l'azione:

  • ICON_IMAGE: dimensioni ridotte e tinta unita
  • SMALL_IMAGE: dimensioni ridotte e non colorazione
  • LARGE_IMAGE: dimensione più grande e non identificabile

Creazione intestazioni

Nella maggior parte dei casi, devi impostare un'intestazione per il modello utilizzando un HeaderBuilder. Un'intestazione può supportare quanto segue:

  • Titolo
  • Sottotitolo
  • Sottotitolo riepilogo
  • Azione principale

Di seguito sono riportati alcuni esempi di configurazioni delle intestazioni. Tieni presente che le caselle grigie mostrano le potenziali posizioni di icone e spaziatura interna:

Rendering delle intestazioni su piattaforme diverse

Quando è necessaria una sezione, la superficie di visualizzazione determina come eseguire il rendering della sezione. Tieni presente che il rendering potrebbe essere leggermente diverso tra le piattaforme di hosting.

Nei formati più piccoli, in genere viene visualizzata solo l'intestazione, se ne esiste una. Se hai specificato un riepilogo per l'intestazione, viene visualizzato il testo del riepilogo anziché quello del sottotitolo.

Se non hai specificato un'intestazione nel modello, in genere viene visualizzata la prima riga aggiunta a ListBuilder.

Esempio di HeaderBuilder - Semplice sezione di elenco con intestazione

Kotlin

fun createSliceWithHeader(sliceUri: Uri) =
    list(context, sliceUri, ListBuilder.INFINITY) {
        setAccentColor(0xff0F9D) // Specify color for tinting icons
        header {
            title = "Get a ride"
            subtitle = "Ride in 4 min"
            summary = "Work in 1 hour 45 min | Home in 12 min"
        }
        row {
            title = "Home"
            subtitle = "12 miles | 12 min | $9.00"
            addEndItem(
                IconCompat.createWithResource(context, R.drawable.ic_home),
                ListBuilder.ICON_IMAGE
            )
        }
    }

Java

public Slice createSliceWithHeader(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }

    // Construct the parent.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            .setAccentColor(0xff0F9D58) // Specify color for tinting icons.
            .setHeader( // Create the header and add to slice.
                    new HeaderBuilder()
                            .setTitle("Get a ride")
                            .setSubtitle("Ride in 4 min.")
                            .setSummary("Work in 1 hour 45 min | Home in 12 min.")
            ).addRow(new RowBuilder() // Add a row.
                    .setPrimaryAction(
                            createActivityAction()) // A slice always needs a SliceAction.
                    .setTitle("Home")
                    .setSubtitle("12 miles | 12 min | $9.00")
                    .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_home),
                            SliceHints.ICON_IMAGE)
            ); // Add more rows if needed...
    return listBuilder.build();
}

SliceActions nelle intestazioni

Le intestazioni delle sezioni possono anche visualizzare SliceActions:

Kotlin

fun createSliceWithActionInHeader(sliceUri: Uri): Slice {
    // Construct our slice actions.
    val noteAction = SliceAction.create(
        takeNoteIntent,
        IconCompat.createWithResource(context, R.drawable.ic_pencil),
        ICON_IMAGE,
        "Take note"
    )

    val voiceNoteAction = SliceAction.create(
        voiceNoteIntent,
        IconCompat.createWithResource(context, R.drawable.ic_mic),
        ICON_IMAGE,
        "Take voice note"
    )

    val cameraNoteAction = SliceAction.create(
        cameraNoteIntent,
        IconCompat.createWithResource(context, R.drawable.ic_camera),
        ICON_IMAGE,
        "Create photo note"
    )

    // Construct the list.
    return list(context, sliceUri, ListBuilder.INFINITY) {
        setAccentColor(0xfff4b4) // Specify color for tinting icons
        header {
            title = "Create new note"
            subtitle = "Easily done with this note taking app"
        }
        addAction(noteAction)
        addAction(voiceNoteAction)
        addAction(cameraNoteAction)
    }
}

Java

public Slice createSliceWithActionInHeader(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Construct our slice actions.
    SliceAction noteAction = SliceAction.create(takeNoteIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_pencil),
            ListBuilder.ICON_IMAGE, "Take note");

    SliceAction voiceNoteAction = SliceAction.create(voiceNoteIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_mic),
            ListBuilder.ICON_IMAGE,
            "Take voice note");

    SliceAction cameraNoteAction = SliceAction.create(cameraNoteIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_camera),
            ListBuilder.ICON_IMAGE,
            "Create photo note");


    // Construct the list.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            .setAccentColor(0xfff4b400) // Specify color for tinting icons
            .setHeader(new HeaderBuilder() // Construct the header.
                    .setTitle("Create new note")
                    .setSubtitle("Easily done with this note taking app")
            )
            .addRow(new RowBuilder()
                    .setTitle("Enter app")
                    .setPrimaryAction(createActivityAction())
            )
            // Add the actions to the ListBuilder.
            .addAction(noteAction)
            .addAction(voiceNoteAction)
            .addAction(cameraNoteAction);
    return listBuilder.build();
}

Creazione righe

Puoi creare una riga di contenuti utilizzando un RowBuilder. Una riga può supportare quanto segue:

  • Titolo
  • Sottotitolo
  • Elemento iniziale: SliceAction, Icona o un timestamp
  • Elementi finali: SliceAction, Icona o un timestamp
  • Azione principale

Puoi combinare i contenuti delle righe in diversi modi, rispettando le seguenti limitazioni:

  • Gli elementi iniziali non verranno visualizzati nella prima riga di una sezione
  • Gli elementi finali non possono essere una combinazione di SliceAction oggetti e Icon oggetti
  • Una riga può contenere un solo timestamp

Nelle seguenti immagini vengono mostrate righe di contenuti di esempio. Tieni presente che le caselle grigie mostrano potenziali posizioni per le icone e la spaziatura interna:

Esempio di RowBuilder - Attivazione/disattivazione Wi-Fi

L'esempio seguente mostra una riga con un'azione principale e un pulsante di attivazione/disattivazione predefinito.

Kotlin

fun createActionWithActionInRow(sliceUri: Uri): Slice {
    // Primary action - open wifi settings.
    val wifiAction = SliceAction.create(
        wifiSettingsPendingIntent,
        IconCompat.createWithResource(context, R.drawable.ic_wifi),
        ICON_IMAGE,
        "Wi-Fi Settings"
    )

    // Toggle action - toggle wifi.
    val toggleAction = SliceAction.createToggle(
        wifiTogglePendingIntent,
        "Toggle Wi-Fi",
        isConnected /* isChecked */
    )

    // Create the parent builder.
    return list(context, wifiUri, ListBuilder.INFINITY) {
        setAccentColor(0xff4285) // Specify color for tinting icons / controls.
        row {
            title = "Wi-Fi"
            primaryAction = wifiAction
            addEndItem(toggleAction)
        }
    }
}

Java

public Slice createActionWithActionInRow(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Primary action - open wifi settings.
    SliceAction primaryAction = SliceAction.create(wifiSettingsPendingIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_wifi),
            ListBuilder.ICON_IMAGE,
            "Wi-Fi Settings"
    );

    // Toggle action - toggle wifi.
    SliceAction toggleAction = SliceAction.createToggle(wifiTogglePendingIntent,
            "Toggle Wi-Fi", isConnected /* isChecked */);

    // Create the parent builder.
    ListBuilder listBuilder = new ListBuilder(getContext(), wifiUri, ListBuilder.INFINITY)
            // Specify color for tinting icons / controls.
            .setAccentColor(0xff4285f4)
            // Create and add a row.
            .addRow(new RowBuilder()
                    .setTitle("Wi-Fi")
                    .setPrimaryAction(primaryAction)
                    .addEndItem(toggleAction));
    // Build the slice.
    return listBuilder.build();
}

Costruttore griglia

Puoi creare una griglia di contenuti utilizzando un GridBuilder. Una griglia può supportare i seguenti tipi di immagine:

  • ICON_IMAGE: dimensioni ridotte e tinta unita
  • SMALL_IMAGE: dimensioni ridotte e non colorazione
  • LARGE_IMAGE: dimensione più grande e non identificabile

Viene creata una cella della griglia mediante un CellBuilder. Una cella può supportare fino a due righe di testo e un'immagine. La cella non può essere vuota.

Gli esempi di griglia sono mostrati nelle seguenti immagini:

Esempio di GridRowBuilder: ristoranti nelle vicinanze

L'esempio seguente mostra una riga della griglia che contiene immagini e testo.

Kotlin

fun createSliceWithGridRow(sliceUri: Uri): Slice {
    // Create the parent builder.
    return list(context, sliceUri, ListBuilder.INFINITY) {
        header {
            title = "Famous restaurants"
            primaryAction = SliceAction.create(
                pendingIntent, icon, ListBuilder.ICON_IMAGE, "Famous restaurants"
            )
        }
        gridRow {
            cell {
                addImage(image1, LARGE_IMAGE)
                addTitleText("Top Restaurant")
                addText("0.3 mil")
                contentIntent = intent1
            }
            cell {
                addImage(image2, LARGE_IMAGE)
                addTitleText("Fast and Casual")
                addText("0.5 mil")
                contentIntent = intent2
            }
            cell {
                addImage(image3, LARGE_IMAGE)
                addTitleText("Casual Diner")
                addText("0.9 mi")
                contentIntent = intent3
            }
            cell {
                addImage(image4, LARGE_IMAGE)
                addTitleText("Ramen Spot")
                addText("1.2 mi")
                contentIntent = intent4
            }
        }
    }
}

Java

public Slice createSliceWithGridRow(Uri sliceUri) {
      if (getContext() == null) {
          return null;
      }
      // Create the parent builder.
      ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
              .setHeader(
                      // Create the header.
                      new HeaderBuilder()
                              .setTitle("Famous restaurants")
                              .setPrimaryAction(SliceAction
                                      .create(pendingIntent, icon, ListBuilder.ICON_IMAGE,
                                              "Famous restaurants"))
              )
              // Add a grid row to the list.
              .addGridRow(new GridRowBuilder()
                      // Add cells to the grid row.
                      .addCell(new CellBuilder()
                              .addImage(image1, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Top Restaurant")
                              .addText("0.3 mil")
                              .setContentIntent(intent1)
                      ).addCell(new CellBuilder()
                              .addImage(image2, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Fast and Casual")
                              .addText("0.5 mil")
                              .setContentIntent(intent2)
                      )
                      .addCell(new CellBuilder()
                              .addImage(image3, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Casual Diner")
                              .addText("0.9 mi")
                              .setContentIntent(intent3))
                      .addCell(new CellBuilder()
                              .addImage(image4, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Ramen Spot")
                              .addText("1.2 mi")
                              .setContentIntent(intent4))
                      // Every slice needs a primary action.
                      .setPrimaryAction(createActivityAction())
              );
      return listBuilder.build();
  }

Generatore di intervalli

Con RangeBuilder puoi creare una riga contenente una barra di avanzamento o un intervallo di input, ad esempio un dispositivo di scorrimento.

Nelle seguenti immagini sono mostrati esempi di avanzamento e dispositivi di scorrimento:

Esempio di RangeBuilder - Dispositivo di scorrimento

L'esempio seguente mostra come creare una sezione contenente un dispositivo di scorrimento di volume utilizzando un elemento InputRangeBuilder. Per creare una riga di avanzamento, utilizza addRange().

Kotlin

fun createSliceWithRange(sliceUri: Uri): Slice {
    return list(context, sliceUri, ListBuilder.INFINITY) {
        inputRange {
            title = "Ring Volume"
            inputAction = volumeChangedPendingIntent
            max = 100
            value = 30
        }
    }
}

Java

public Slice createSliceWithRange(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Construct the parent.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            .addRow(new RowBuilder() // Every slice needs a row.
                    .setTitle("Enter app")
                      // Every slice needs a primary action.
                    .setPrimaryAction(createActivityAction())
            )
            .addInputRange(new InputRangeBuilder() // Create the input row.
                    .setTitle("Ring Volume")
                    .setInputAction(volumeChangedPendingIntent)
                    .setMax(100)
                    .setValue(30)
            );
    return listBuilder.build();
}

Contenuti in ritardo

Devi restituire una sezione il più rapidamente possibile a partire dal giorno SliceProvider.onBindSlice(). Le chiamate dispendiose in termini di tempo possono causare problemi di visualizzazione, ad esempio sfarfallio e ridimensionamenti improvvisi.

Se hai contenuti della sezione che non possono essere caricati rapidamente, puoi creare la sezione con contenuti segnaposto mentre noti nello strumento di creazione che il contenuto è in fase di caricamento. Quando il contenuto è pronto per essere visualizzato, chiama getContentResolver().notifyChange(sliceUri, null) utilizzando il tuo URI Slice. Ciò comporta un'altra chiamata a SliceProvider.onBindSlice(), dove potrai creare di nuovo la sezione con contenuti aggiornati.

Esempio di contenuti in ritardo - Corsa al lavoro

Nella riga Corsa al lavoro qui sotto, la distanza dal lavoro è determinata in modo dinamico e potrebbe non essere subito disponibile. Il codice di esempio mostra l'uso di un sottotitolo nullo come segnaposto durante il caricamento dei contenuti:

Kotlin

fun createSliceShowingLoading(sliceUri: Uri): Slice {
    // We’re waiting to load the time to work so indicate that on the slice by
    // setting the subtitle with the overloaded method and indicate true.
    return list(context, sliceUri, ListBuilder.INFINITY) {
        row {
            title = "Ride to work"
            setSubtitle(null, true)
            addEndItem(IconCompat.createWithResource(context, R.drawable.ic_work), ICON_IMAGE)
        }
    }
}

Java

public Slice createSliceShowingLoading(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Construct the parent.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            // Construct the row.
            .addRow(new RowBuilder()
                    .setPrimaryAction(createActivityAction())
                    .setTitle("Ride to work")
                    // We’re waiting to load the time to work so indicate that on the slice by
                    // setting the subtitle with the overloaded method and indicate true.
                    .setSubtitle(null, true)
                    .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_work),
                            ListBuilder.ICON_IMAGE)
            );
    return listBuilder.build();
}

private SliceAction createActivityAction() {
    return SliceAction.create(
            PendingIntent.getActivity(
                    getContext(),
                    0,
                    new Intent(getContext(), MainActivity.class),
                    0
            ),
            IconCompat.createWithResource(getContext(), R.drawable.ic_home),
            ListBuilder.ICON_IMAGE,
            "Enter app"
    );
}

Gestire lo scorrimento disattivato all'interno della sezione

La piattaforma in cui viene presentato il modello Sezione potrebbe non supportare lo scorrimento all'interno del modello. In tal caso, alcuni dei tuoi contenuti potrebbero non essere visualizzati.

Prendiamo come esempio una Sezione che mostra un elenco di reti Wi-Fi:

Se l'elenco Wi-Fi è lungo e se lo scorrimento è disattivato, puoi aggiungere un pulsante Mostra altro per assicurarti che gli utenti possano visualizzare tutti gli elementi nell'elenco. Puoi aggiungere questo pulsante utilizzando addSeeMoreAction(), come mostrato nell'esempio seguente:

Kotlin

fun seeMoreActionSlice(sliceUri: Uri) =
    list(context, sliceUri, ListBuilder.INFINITY) {
        // [START_EXCLUDE]
        // [END_EXCLUDE]
        setSeeMoreAction(seeAllNetworksPendingIntent)
        // [START_EXCLUDE]
        // [END_EXCLUDE]
    }

Java

public Slice seeMoreActionSlice(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY);
    // [START_EXCLUDE]
    listBuilder.addRow(new RowBuilder()
            .setTitle("Hello")
            .setPrimaryAction(createActivityAction())
    );
    // [END_EXCLUDE]
    listBuilder.setSeeMoreAction(seeAllNetworksPendingIntent);
    // [START_EXCLUDE]
    // [END_EXCLUDE]
    return listBuilder.build();
}

Viene visualizzato come nell'immagine seguente:

Se tocchi Mostra altro, invii seeAllNetworksPendingIntent.

In alternativa, se vuoi fornire una riga o un messaggio personalizzato, valuta la possibilità di aggiungere RowBuilder:

Kotlin

fun seeMoreRowSlice(sliceUri: Uri) =
    list(context, sliceUri, ListBuilder.INFINITY) {
        // [START_EXCLUDE]
        // [END_EXCLUDE]
        seeMoreRow {
            title = "See all available networks"
            addEndItem(
                IconCompat.createWithResource(context, R.drawable.ic_right_caret), ICON_IMAGE
            )
            primaryAction = SliceAction.create(
                seeAllNetworksPendingIntent,
                IconCompat.createWithResource(context, R.drawable.ic_wifi),
                ListBuilder.ICON_IMAGE,
                "Wi-Fi Networks"
            )
        }
    }

Java

public Slice seeMoreRowSlice(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            // [START_EXCLUDE]
            .addRow(new RowBuilder()
                    .setTitle("Hello")
                    .setPrimaryAction(createActivityAction())
            )
            // [END_EXCLUDE]
            .setSeeMoreRow(new RowBuilder()
                    .setTitle("See all available networks")
                    .addEndItem(IconCompat
                                    .createWithResource(getContext(), R.drawable
                                            .ic_right_caret),
                            ListBuilder.ICON_IMAGE)
                    .setPrimaryAction(SliceAction.create(seeAllNetworksPendingIntent,
                            IconCompat.createWithResource(getContext(), R.drawable.ic_wifi),
                            ListBuilder.ICON_IMAGE,
                            "Wi-Fi Networks"))
            );
    // [START_EXCLUDE]
    // [END_EXCLUDE]
    return listBuilder.build();
}

La riga o l'azione aggiunta con questo metodo viene visualizzata solo quando è soddisfatta una delle seguenti condizioni:

  • Il presentatore della sezione ha disattivato lo scorrimento nella visualizzazione
  • Non tutte le righe possono essere visualizzate nello spazio disponibile

Combinare i modelli

Puoi creare una sezione ricca e dinamica combinando più tipi di righe. Ad esempio, una sezione può contenere una riga di intestazione, una griglia con una singola immagine e una griglia con due celle di testo.

Ecco una sezione con una riga di intestazione e una griglia che contiene tre celle.