Este documento traz detalhes sobre como usar os builders de modelo no Android Jetpack para criar Slices.
Definir seu modelo Slice
Os Slices são criados com um
ListBuilder
. O ListBuilder
permite adicionar diferentes tipos de linhas que são exibidas em uma lista. Esta
seção descreve cada um desses tipos de linha e como eles são criados.
SliceAction
O elemento mais básico de um modelo Slice é uma
SliceAction
. Uma SliceAction
contém uma etiqueta junto com um
PendingIntent
e pode ser um dos
itens a seguir:
- Botão de ícone
- Alternância padrão
- Alternância personalizada (drawable com um estado ativado/desativado)
A SliceAction
é usada pelos builders de modelo descritos no restante desta
seção. Uma SliceAction
pode ter um modo de imagem definido que determina como a
imagem será apresentada para a ação:
ICON_IMAGE
: tamanho muito pequeno e coloridaSMALL_IMAGE
: tamanho pequeno e não coloridaLARGE_IMAGE
: tamanho máximo e não colorida
HeaderBuilder
Na maioria dos casos, é preciso definir um cabeçalho para o modelo usando um
HeaderBuilder
.
Um cabeçalho pode ser compatível com:
- Título
- Subtítulo
- Subtítulo de resumo
- Ação principal
Veja abaixo alguns exemplos de configurações de cabeçalho. As caixas cinza mostram possíveis locais de ícones e padding:
Renderização de cabeçalho em diferentes superfícies
Quando um Slice é necessário, a superfície em exibição determina como renderizá-lo. A renderização pode apresentar algumas diferenças entre as superfícies de hospedagem.
Em formatos menores, apenas o cabeçalho, se existir, costuma ser exibido. Se você especificou um resumo para o cabeçalho, o texto do resumo será exibido em vez do texto do subtítulo.
Se você não especificou um cabeçalho no modelo, a primeira linha adicionada ao
ListBuilder
é geralmente exibida.
Exemplo de HeaderBuilder: Slice de lista simples com cabeçalho
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 nos cabeçalhos
Os cabeçalhos de Slices também podem exibir 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
Você pode criar uma linha de conteúdo por meio de um
RowBuilder
. Uma linha
pode ser compatível com qualquer destes itens:
- Título
- Subtítulo
- Item de início: SliceAction, ícone ou carimbo de data/hora
- Itens de término: SliceAction, ícone ou carimbo de data/hora
- Ação principal
É possível combinar conteúdos de linha de várias formas, de acordo com as seguintes restrições:
- Os itens de início não são exibidos na primeira linha de um Slice.
- Os itens de término não podem ser uma mistura de objetos
SliceAction
eIcon
. - Uma linha pode conter apenas um carimbo de data/hora.
Veja exemplos de linha de conteúdo nas imagens a seguir. As caixas cinza mostram possíveis locais de ícones e padding:
Exemplo de RowBuilder: alternância de Wi-Fi
O exemplo abaixo demonstra uma linha com uma ação principal e uma alternância padrão.
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
Você pode criar uma grade de conteúdo por meio de um
GridBuilder
. Uma grade pode
ser compatível com os seguintes tipos de imagem:
ICON_IMAGE
: tamanho muito pequeno e coloridaSMALL_IMAGE
: tamanho pequeno e não coloridaLARGE_IMAGE
: tamanho máximo e não colorida
Uma célula de grade é criada com um
CellBuilder
. Uma
célula pode ser compatível com até duas linhas de texto e uma imagem. Uma célula não pode ficar vazia.
Veja exemplos de grade nas imagens a seguir:
Exemplo de GridRowBuilder: restaurantes por perto
O exemplo abaixo demonstra uma linha de grade que contém imagens e texto.
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
Com um
RangeBuilder
,
você pode criar uma linha que contenha uma barra de progresso ou um intervalo de entrada, como
um controle deslizante.
Veja exemplos de barra de progresso e controle deslizante nas seguintes imagens:
Exemplo de RangeBuilder: controle deslizante
O exemplo abaixo demonstra como criar um Slice que contém um controle
deslizante de volume por meio de um InputRangeBuilder
. Para criar uma linha de progresso, use
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(); }
Conteúdo atrasado
Retorne um Slice o mais rápido possível a partir de
SliceProvider.onBindSlice()
.
Chamadas demoradas podem causar problemas de exibição, como oscilações e redimensionamento
abrupto.
Se você tiver conteúdo de Slice que não pode ser carregado rapidamente, crie o
Slice com conteúdo de marcador e observe no builder que o
conteúdo está carregando. Quando o conteúdo estiver pronto para exibição, chame
getContentResolver().notifyChange(sliceUri, null)
por meio do URI do Slice. Isso resultará em outra chamada para
SliceProvider.onBindSlice()
, em que você pode criar o Slice novamente com conteúdo
novo.
Exemplo de conteúdo atrasado: deslocamento para o trabalho
Na linha "Ride to work" abaixo, a distância até o trabalho é determinada dinamicamente e pode não estar disponível de imediato. O exemplo de código demonstra o uso de um subtítulo nulo como marcador enquanto o conteúdo é carregado:
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" ); }
Processar rolagem desativada no Slice
A superfície que apresenta seu modelo Slice pode não ser compatível com a rolagem no modelo. Nesse caso, parte do conteúdo pode não ser exibida.
Por exemplo, considere um Slice que exibe uma lista de redes Wi-Fi:
Se a lista de Wi-Fi for longa e a rolagem estiver desativada, você poderá adicionar um
botão Ver mais para que os usuários possam ver todos os itens
da lista. Para adicionar esse botão, use
addSeeMoreAction()
,
conforme mostrado no exemplo a seguir:
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(); }
O resultado pode ser visto nesta imagem:
O toque em Ver mais envia seeAllNetworksPendingIntent
.
Como alternativa, se você quiser mostrar uma mensagem ou linha personalizada, adicione um 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(); }
A linha ou ação adicionada por esse método é exibida apenas quando uma das seguintes condições é atendida:
- O apresentador do Slice desativou a rolagem na visualização.
- Nem todas as linhas podem ser exibidas no espaço disponível.
Combinar modelos
É possível criar um Slice avançado e dinâmico combinando vários tipos de linha. Por exemplo, um Slice pode conter uma linha de cabeçalho, uma grade com uma única imagem e uma grade com duas células de texto.
Veja um Slice com uma linha de cabeçalho e uma grade com três células.