Criar um layout de detalhes e listas

Os detalhes e listas são um padrão da interface 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 essenciais, como dividir as preferências do app em uma lista de categorias com as preferências de cada uma no painel de detalhes.

Implementar o padrão da interface com ListDetailPaneScaffold

O ListDetailPaneScaffold é um elemento combinável que simplifica a implementação do padrão de detalhes e listas no app. Um scaffolding de detalhes e listas pode consistir em até três painéis: um de lista, um de detalhes e outro opcional. O scaffold processa cálculos do espaço da tela. Quando um tamanho de tela suficiente estiver disponível, o painel de detalhes vai ser exibido ao lado do painel de lista. Em tamanhos de tela pequenos, o scaffold muda automaticamente para mostrar a lista ou o painel de detalhes em tela cheia.

Um painel de detalhes mostrado ao lado da página da lista.
Figura 1. Quando um tamanho de tela suficiente estiver disponível, o painel de detalhes vai ser mostrado ao lado do painel da lista.
Depois que um item é selecionado, o painel de detalhes ocupa toda a tela.
Figura 2. Quando o tamanho da tela é limitado, o painel de detalhes (já que um item foi selecionado) ocupa todo o espaço.

Declarar dependências

O ListDetailPaneScaffold faz parte da biblioteca de layout adaptável do Material 3.

Seu app precisa incluir dependências para três bibliotecas relacionadas do Material 3:

  • adaptáveis: elementos básicos de nível inferior, como HingeInfo e Posture
  • adaptive-layout: layouts adaptáveis, como ListDetailPaneScaffold e SupportingPaneScaffold.
  • adaptive-navigation: elementos combináveis para navegar dentro e entre painéis.

Adicione as dependências ao arquivo build.gradle do seu app ou módulo:

Kotlin


implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha12")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha12")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha12")

Groovy


implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha12'

Uso básico

Implemente ListDetailPaneScaffold desta forma:

  1. Use uma classe que represente o conteúdo a ser selecionado. Essa classe precisa ser Parcelable para oferecer suporte ao salvamento e restauração do item da lista selecionado. Use o plug-in kotlin-parcelize para gerar o código.

    @Parcelize
    class MyItem(val id: Int) : Parcelable

  2. Crie um ThreePaneScaffoldNavigator com rememberListDetailPaneScaffoldNavigator e adicione um BackHandler. Esse navegador é usado para alternar entre a lista, os detalhes e os painéis extras. Ao declarar um tipo genérico, o navegador também rastreia o estado do scaffold, ou seja, qual MyItem está sendo mostrada. Como esse tipo é parcelable, o estado pode ser salvo e restaurado pelo navegador para processar automaticamente mudanças de configuração. O BackHandler oferece suporte para navegar de volta usando o gesto ou botão "Voltar" do sistema. O comportamento esperado do botão "Voltar" para uma ListDetailPaneScaffold depende do tamanho da janela e do valor do scaffold atual. Se o ListDetailPaneScaffold for compatível com a volta ao estado atual, canNavigateBack() será true, ativando o BackHandler.

    val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. Transmita o scaffoldState do navigator para o elemento combinável ListDetailPaneScaffold.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. Forneça a implementação do painel de lista ao ListDetailPaneScaffold. Use AnimatedPane para aplicar as animações do painel padrão durante a navegação. Em seguida, use ThreePaneScaffoldNavigator para navegar até o painel de detalhes, ListDetailPaneScaffoldRole.Detail, e mostrar o item transmitido.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                MyList(
                    onItemClick = { item ->
                        // Navigate to the detail pane with the passed item
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                    }
                )
            }
        },
        // ...
    )

  5. Inclua a implementação do painel de detalhes no ListDetailPaneScaffold. Quando a navegação é concluída, currentDestination contém o painel que seu app acessou, incluindo o conteúdo mostrado nele. A propriedade content é do mesmo tipo especificado na chamada de remember original (MyItem neste exemplo), então você também pode acessar a propriedade para todos os dados que precisar exibir.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane {
                navigator.currentDestination?.content?.let {
                    MyDetails(it)
                }
            }
        },
    )

Depois de implementar as etapas acima, o código vai ficar parecido com este:

val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            navigator.currentDestination?.content?.let {
                MyDetails(it)
            }
        }
    },
)