Ce document explique comment utiliser les compilateurs 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 élément ListBuilder
. ListBuilder vous permet d'ajouter différents types de lignes affichées dans une liste. Cette section décrit chacun de ces types de lignes et la façon dont ils sont construits.
Action SliceAction (SliceAction)
L'élément le plus basique d'un modèle de segment d'application est un élément SliceAction
. Un SliceAction
contient un libellé ainsi qu'un élément PendingIntent
. Il correspond à l'un des éléments suivants:
- Bouton d'icône
- Activer/Désactiver par défaut
- Bouton d'activation personnalisé (drawable avec un état activé/désactivé)
SliceAction
est utilisé par les compilateurs de modèles décrits dans le reste de cette section. Un SliceAction
peut avoir un mode d'image défini qui détermine la façon dont l'image est présentée pour l'action:
ICON_IMAGE
: petite taille et teintéeSMALL_IMAGE
: petite taille et non teintéeLARGE_IMAGE
: plus grande taille et non teinté
Générateur d'en-têtes
Dans la plupart des cas, vous devez définir un en-tête pour votre modèle à l'aide d'un HeaderBuilder
.
Un en-tête peut accepter les éléments suivants:
- Titre
- Sous-titre
- Sous-titre récapitulatif
- Action principale
Vous trouverez ci-dessous quelques exemples de configurations d'en-tête. Notez que les zones grises indiquent l'icône et l'emplacement potentiels de la marge intérieure:
Rendu de l'en-tête sur différentes surfaces
Lorsqu'un segment d'application est nécessaire, la surface d'affichage détermine comment l'afficher. Notez que le rendu peut varier légèrement entre les surfaces d'hébergement.
Dans les formats plus petits, seul l'en-tête s'affiche généralement, le cas échéant. Si vous avez spécifié un résumé pour l'en-tête, le texte récapitulatif est affiché à la place 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
s'affiche généralement à la place.
Exemple de HeaderBuilder – Tranche 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 segments d'application peuvent également afficher des actions de segment d'application:
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 créer une ligne de contenu à l'aide d'un RowBuilder
. Une ligne peut accepter l'un des éléments suivants:
- Titre
- Sous-titre
- Élément de début: 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, sous réserve des restrictions suivantes:
- Les éléments de début ne s'affichent pas sur la première ligne d'un segment d'application
- Les éléments de fin ne peuvent pas être une combinaison d'objets
SliceAction
etIcon
- Une ligne ne peut contenir qu'un seul code temporel
Les images suivantes présentent des exemples de lignes de contenu. Notez que les zones grises indiquent les emplacements potentiels de l'icône et de la marge intérieure:
Exemple de RowBuilder – Activation/Désactivation du Wi-Fi
L'exemple ci-dessous présente une ligne avec une action principale et un bouton d'activation/désactivation 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 créer une grille de contenu à l'aide d'un GridBuilder
. Une grille peut accepter les types d'images suivants:
ICON_IMAGE
: petite taille et teintéeSMALL_IMAGE
: petite taille et non teintéeLARGE_IMAGE
: plus grande taille et non teinté
Une cellule de grille est construite à l'aide d'un élément CellBuilder
. Une cellule peut accepter jusqu'à deux lignes de texte et une image. Une cellule ne peut pas être vide.
Des exemples de grille sont illustrés dans les images suivantes:
Exemple 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(); }
Créateur de plages
Un RangeBuilder
vous permet de créer une ligne contenant une barre de progression ou une plage d'entrée, telle qu'un curseur.
Les images suivantes présentent des exemples de progression et de curseur:
Exemple RangeBuilder – Curseur
L'exemple ci-dessous montre comment créer un segment d'application contenant un curseur de volume à 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 différé
Vous devez renvoyer un segment d'application le plus rapidement possible à partir de SliceProvider.onBindSlice()
.
Les appels chronophages peuvent entraîner des problèmes d'affichage, tels qu'un scintillement ou un redimensionnement brusque.
Si le contenu du segment d'application ne peut pas être chargé rapidement, vous pouvez créer votre segment d'application avec un contenu d'espace réservé tout en indiquant dans le compilateur que ce 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 du segment d'application. Cela entraîne un autre appel à SliceProvider.onBindSlice()
, où vous pouvez reconstruire le segment d'application avec un nouveau contenu.
Exemple de contenu retardé : trajet jusqu'au travail
Dans la ligne "Trajet au travail" ci-dessous, la distance jusqu'au travail est déterminée de manière dynamique et peut ne pas être disponible immédiatement. L'exemple de code illustre l'utilisation d'un sous-titre nul comme espace réservé pendant le 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 qui présente votre modèle de segment d'application peut ne pas être compatible avec le défilement dans le modèle. Dans ce cas, une partie de votre contenu peut ne pas s'afficher.
Prenons l'exemple d'un segment d'application affichant une liste de réseaux Wi-Fi:
Si la liste des réseaux Wi-Fi est longue et que le défilement est désactivé, vous pouvez ajouter un bouton See more (Voir plus) pour vous assurer que les utilisateurs ont la possibilité d'afficher tous les éléments de la liste. Vous pouvez ajouter ce bouton à l'aide de addSeeMoreAction()
, comme indiqué 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(); }
Cela s'affiche comme illustré dans l'image suivante:
Si vous appuyez sur Voir plus, vous envoyez seeAllNetworksPendingIntent
.
Si vous souhaitez fournir un message ou une ligne personnalisés, vous pouvez également ajouter un 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 via cette méthode ne s'affiche que si l'une des conditions suivantes 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 s'afficher dans l'espace disponible
Combiner des modèles
Vous pouvez créer un segment d'application dynamique et enrichi en combinant plusieurs types de lignes. Par 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 d'application avec une ligne d'en-tête et une grille contenant trois cellules.