Detalhes e listas é um padrão de IU que consiste em um layout de painel duplo em que um painel apresenta uma lista de itens e outro mostra os detalhes dos itens selecionados na lista.
O padrão é particularmente útil para aplicativos que fornecem informações detalhadas sobre elementos de grandes coleções, por exemplo, um cliente de e-mail que tem uma lista de e-mails e o conteúdo detalhado de cada mensagem. Os detalhes e listas também podem ser usados para caminhos menos críticos, como dividir as preferências do app em uma lista de categorias com as preferências de cada categoria no painel de detalhes.
Implementar o padrão de detalhes e listas com NavigableListDetailPaneScaffold
NavigableListDetailPaneScaffold é um elemento combinável que simplifica a implementação de um layout de detalhes e listas no Jetpack Compose. Ele envolve ListDetailPaneScaffold e adiciona navegação integrada e animações de volta preditivas.
Um scaffold de detalhes e listas oferece suporte a até três painéis:
- Painel de lista: mostra uma coleção de itens.
- Painel de detalhes: mostra os detalhes de um item selecionado.
- Painel extra (opcional): fornece contexto adicional quando necessário.
O scaffold se adapta com base no tamanho da janela:
- Em janelas grandes, os painéis de lista e de detalhes aparecem lado a lado.
- Em janelas pequenas, apenas um painel fica visível por vez, alternando conforme os usuários navegam.
Declarar dependências
NavigableListDetailPaneScaffold faz parte da biblioteca de navegação adaptável do Material 3.
Adicione as três dependências relacionadas a seguir ao arquivo build.gradle do app ou módulo:
Kotlin
implementation("androidx.compose.material3.adaptive:adaptive") implementation("androidx.compose.material3.adaptive:adaptive-layout") implementation("androidx.compose.material3.adaptive:adaptive-navigation")
Groovy
implementation 'androidx.compose.material3.adaptive:adaptive' implementation 'androidx.compose.material3.adaptive:adaptive-layout' implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
- adaptive: blocos de construção de baixo nível, como
HingeInfoePosture - adaptive-layout: layouts adaptáveis, como
ListDetailPaneScaffoldeSupportingPaneScaffold - adaptive-navigation: elementos combináveis para navegar dentro e entre painéis, bem como layouts adaptáveis que oferecem suporte à navegação por padrão, como
NavigableListDetailPaneScaffoldeNavigableSupportingPaneScaffold
Verifique se o projeto inclui a versão 1.1.0-beta1 ou mais recente do compose-material3-adaptive.
Ativar o gesto de volta preditivo
Para ativar animações de volta preditivas no Android 15 ou versões anteriores, é necessário ativar o suporte ao gesto de volta preditivo. Para ativar, adicione
android:enableOnBackInvokedCallback="true" à tag <application> ou
às tags <activity> individuais no arquivo AndroidManifest.xml. Para mais
informações, consulte Ativar o gesto de volta preditivo.
Quando o app é destinado ao Android 16 (nível 36 da API) ou mais recente, a volta preditiva é ativada por padrão.
Uso básico
Implemente NavigableListDetailPaneScaffold da seguinte maneira:
- Use uma classe que represente o conteúdo selecionado. Use uma
Parcelableclasse para oferecer suporte ao salvamento e à restauração do item de lista selecionado. Use o plug-in kotlin-parcelize para gerar o código. - Crie um
ThreePaneScaffoldNavigatorcomrememberListDetailPaneScaffoldNavigator.
Esse navegador é usado para se mover entre os painéis de lista, detalhes e extras. Ao declarar um tipo genérico, o navegador também rastreia o estado do scaffold (ou seja, qual MyItem está sendo mostrado). Como esse tipo é parcelável, o estado pode ser salvo e restaurado pelo navegador para processar automaticamente as mudanças de configuração.
Transmita o navegador para o elemento combinável
NavigableListDetailPaneScaffold.Forneça a implementação do painel de lista para
NavigableListDetailPaneScaffold. UseAnimatedPanepara aplicar as animações de painel padrão durante a navegação. Em seguida, useThreePaneScaffoldNavigatorpara navegar até o painel de detalhes,ListDetailPaneScaffoldRole.Detail, e mostrar o item transmitido.Inclua a implementação do painel de detalhes em
NavigableListDetailPaneScaffold.
Quando a navegação é concluída, currentDestination contém o painel para o qual o app navegou, incluindo o conteúdo mostrado no painel. A propriedade contentKey é o mesmo tipo especificado na chamada original, para que você possa acessar todos os dados que precisa mostrar.
- Opcionalmente, mude o
defaultBackBehavioremNavigableListDetailPaneScaffold. Por padrão,NavigableListDetailPaneScaffoldusaPopUntilScaffoldValueChangeparadefaultBackBehavior.
Se o app exigir um padrão de navegação de retorno diferente, você poderá substituir esse comportamento especificando outra opção BackNavigationBehavior.
Opções BackNavigationBehavior
A seção a seguir usa o exemplo de um app de e-mail com uma lista de e-mails em um painel e uma visualização detalhada no outro.
PopUntilScaffoldValueChange (padrão e recomendado na maioria dos casos)
Esse comportamento se concentra em mudanças na estrutura geral do layout. Em uma configuração de vários painéis, mudar o conteúdo do e-mail no painel detalhado não altera a estrutura do layout subjacente. Portanto, o botão "Voltar" pode sair do app ou do gráfico de navegação atual porque não há mudança de layout para reverter no contexto atual. Em um layout de painel único, pressionar "Voltar" vai pular as mudanças de conteúdo na visualização de detalhes e retornar à visualização de lista, já que isso representa uma mudança clara de layout.
Confira estes exemplos:
- Vários painéis:você está visualizando um e-mail (item 1) no painel de detalhes. Clicar em outro e-mail (item 2) atualiza o painel de detalhes, mas os painéis de lista e de detalhes permanecem visíveis. Pressionar "Voltar" pode sair do app ou do fluxo de navegação atual.
- Painel único:você visualiza o item 1 e, em seguida, o item 2. Pressionar "Voltar" vai retornar diretamente ao painel de lista de e-mails.
Use isso quando quiser que os usuários percebam transições de layout distintas com cada ação de volta.
PopUntilContentChange
Esse comportamento prioriza o conteúdo mostrado. Se você visualizar o item 1 e, em seguida, o item 2, pressionar "Voltar" vai reverter para o item 1, independentemente do layout.
Confira estes exemplos:
- Vários painéis:você visualiza o item 1 no painel de detalhes e clica no item 2 na lista. O painel de detalhes é atualizado. Pressionar "Voltar" vai restaurar o painel de detalhes para o item 1.
- Painel único:a mesma reversão de conteúdo ocorre.
Use isso quando o usuário espera retornar ao conteúdo visualizado anteriormente com a ação de volta.
PopUntilCurrentDestinationChange
Esse comportamento remove a backstack até que o destino de navegação atual mude. Isso se aplica igualmente a layouts de painel único e de vários painéis.
Confira estes exemplos:
Independentemente de você estar em um layout de painel único ou de vários painéis, pressionar "Voltar" sempre vai mover o foco do elemento de navegação destacado para o destino anterior. No nosso app de e-mail, isso significa que a indicação visual do painel selecionado será alterada.
Use isso quando manter uma indicação visual clara da navegação atual for crucial para a experiência do usuário.
PopLatest
Essa opção remove apenas o destino mais recente da backstack. Use essa opção para navegação de retorno sem pular estados intermediários.
Depois de implementar essas etapas, o código vai ficar parecido com este:
NavigableListDetailPaneScaffold( navigator = navigator, listPane = { AnimatedPane { ListContent( words = sampleWords, selectionState = navigator.currentDestination?.contentKey?.let { SelectionVisibilityState.ShowSelection(it) } ?: SelectionVisibilityState.NoSelection, onWordClick = { word -> scope.launch { navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word) } }, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout ) } }, detailPane = { AnimatedPane { DetailContent( definedWord = navigator.currentDestination?.contentKey, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout, onClosePane = { scope.launch { navigator.navigateBack( backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange ) } } ) } }