Modèles de Slices

Ce document fournit des détails sur l'utilisation des générateurs de modèles dans Android Jetpack pour créer des segments d'application

Définir votre modèle de segment d'application

Les segments d'application sont construits à l'aide d'un ListBuilder Outil de création de listes vous permet d'ajouter différents types de lignes qui s'affichent dans une liste. Ce décrit chacun de ces types de lignes et leur structure.

ActionSlice

L'élément le plus élémentaire d'un modèle de segment d'application est SliceAction SliceAction contient un libellé ainsi qu'un PendingIntent et est l'un des suivantes:

  • Bouton en forme d'icône
  • Bouton d'activation par défaut
  • Bouton bascule personnalisé (un drawable avec un état activé/désactivé)

SliceAction est utilisé par les outils de création de modèles décrits dans cette suite . Un SliceAction peut avoir un mode d'image défini qui détermine la façon dont est présentée pour l'action:

  • ICON_IMAGE: petite taille et teinté
  • SMALL_IMAGE: petite taille et non teinté
  • LARGE_IMAGE: taille la plus grande et non teintée

En-tête

Dans la plupart des cas, vous devez définir un en-tête pour votre modèle à l'aide d'un en-tête HeaderBuilder Un en-tête peut prendre en charge les éléments suivants:

  • Titre
  • Sous-titre
  • Sous-titre du résumé
  • Action principale

Voici quelques exemples de configurations d'en-tête. Notez que les cases grises emplacements potentiels d'icône et de marge intérieure:

Rendu des en-têtes sur différentes surfaces

Lorsqu'un segment d'application est nécessaire, la surface d'affichage détermine comment afficher Tranche. Notez que l'affichage peut être légèrement différent d'une surface d'hébergement à l'autre.

Dans les formats plus petits, seul l'en-tête est affiché, s'il en existe un. Si vous avez spécifié un résumé pour l'en-tête, le texte de résumé s'affiche à la place le texte du sous-titre.

Si vous n'avez pas spécifié d'en-tête dans votre modèle, la première ligne ajoutée à votre ListBuilder est généralement affiché à la place.

Exemple HeaderBuilder : segment de liste simple avec en-tête

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 dans les en-têtes

Les en-têtes de segment peuvent également afficher les actions 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();
}

RowBuilder

Vous pouvez construire une ligne de contenu en utilisant un RowBuilder Une ligne est compatible avec les éléments suivants:

  • Titre
  • Sous-titre
  • Élément de démarrage: SliceAction, Icon ou un code temporel
  • Éléments de fin: SliceAction, Icon ou un code temporel
  • Action principale

Vous pouvez combiner le contenu des lignes de plusieurs manières, en tenant compte des conditions suivantes : restrictions:

  • Les éléments de début ne s'afficheront pas sur la première ligne d'un segment d'application
  • Les éléments finaux ne peuvent pas être une combinaison d'objets SliceAction et Icon
  • Une ligne ne peut contenir qu'un seul code temporel

Des exemples de lignes de contenu sont présentés dans les images suivantes. Notez que les zones grises afficher les emplacements potentiels pour les icônes et les marges intérieures:

Exemple RowBuilder – Activation/Désactivation du Wi-Fi

L'exemple ci-dessous présente une ligne avec une action principale et un bouton d'activation par défaut.

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

GridBuilder

Vous pouvez construire une grille de contenu en utilisant un GridBuilder Une grille peut sont compatibles avec les types d'images suivants:

  • ICON_IMAGE: petite taille et teinté
  • SMALL_IMAGE: petite taille et non teinté
  • LARGE_IMAGE: taille la plus grande et non teintée

Une cellule de grille est construite à l'aide d'un CellBuilder A peut accepter jusqu'à deux lignes de texte et une image. Une cellule ne peut pas être vide.

Des exemples de grilles sont illustrés dans les images suivantes:

Exemple pour GridRowBuilder – Restaurants à proximité

L'exemple ci-dessous illustre une ligne de grille contenant des images et du texte.

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

RangeBuilder

Avec un RangeBuilder vous pouvez créer une ligne contenant une barre de progression ou une plage d'entrée, par exemple en tant que curseur.

Les images suivantes illustrent la progression et des exemples de curseurs:

Exemple pour RangeBuilder – Curseur

L'exemple ci-dessous montre comment créer un segment d'application contenant un volume. curseur à l'aide d'un InputRangeBuilder. Pour créer une ligne de progression, utilisez 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();
}

Contenu retardé

Vous devez renvoyer un segment d'application le plus rapidement possible SliceProvider.onBindSlice() Les appels qui prennent du temps peuvent entraîner des problèmes d'affichage, tels que des scintillements et des affichages brusques redimensionnement.

Si le contenu de vos segments d'application ne peut pas être chargé rapidement, vous pouvez créer votre Segmenter avec le contenu d'espace réservé tout en notant dans le compilateur que le le contenu est en cours de chargement. Une fois que le contenu est prêt à être affiché, appelez getContentResolver().notifyChange(sliceUri, null) à l'aide de l'URI de votre segment d'application. Cela entraîne un autre appel à SliceProvider.onBindSlice(), où vous pouvez à nouveau construire le segment d'application avec de nouveaux contenus.

Exemple de contenu retardé : aller au travail

Dans la ligne Trajet vers le lieu de travail ci-dessous, la distance jusqu'au lieu de travail est déterminée de façon dynamique et peuvent ne pas être disponibles immédiatement. L'exemple de code illustre l'utilisation d'un Sous-titre nul comme espace réservé lors du chargement du contenu:

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

Gérer le défilement désactivé dans votre segment d'application

La surface présentant votre modèle de segment d'application n'est peut-être pas compatible avec le défilement dans le modèle. Dans ce cas, il est possible qu'une partie de votre contenu ne s'affiche pas.

Prenons l'exemple d'un segment d'application affichant une liste de réseaux Wi-Fi:

Si la liste Wi-Fi est longue et que le défilement n'est pas activé, vous pouvez ajouter une Voir plus pour que les utilisateurs puissent voir tous les éléments du liste. Vous pouvez ajouter ce bouton en utilisant addSeeMoreAction() comme illustré dans l'exemple suivant:

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

Le résultat est le suivant:

Si vous appuyez sur Voir plus, seeAllNetworksPendingIntent est envoyé.

Si vous souhaitez fournir un message ou une ligne personnalisés, vous pouvez également ajouter une 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 ligne ou l'action ajoutée par le biais de cette méthode ne s'affiche que si l'une des conditions suivantes est remplie : est remplie:

  • Le présentateur de votre segment d'application a désactivé le défilement dans la vue
  • Toutes vos lignes ne peuvent pas être affichées dans l'espace disponible

Combiner des modèles

Vous pouvez créer un segment d'application dynamique enrichi en combinant plusieurs types de lignes. Pour exemple, un segment d'application peut contenir une ligne d'en-tête, une grille avec une seule image et une grille avec deux cellules de texte.

Voici un segment avec une ligne d'en-tête et une grille contenant trois cellules.