Criar um layout de detalhes e listas

Detalhes e listas são um padrão de interface que consiste em um layout de painel duplo em que um painel apresenta uma lista de itens e outro painel exibe os detalhes dos itens selecionados da 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 o app preferências em uma lista de categorias, com as preferências de cada categoria em no painel de detalhes.

Implementar o padrão de interface com ListDetailPaneScaffold

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

Um painel de detalhes ao lado da página da lista.
Figura 1. Quando há tamanho de tela suficiente disponível, os detalhes ao lado do painel de 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

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

Adicione as três dependências relacionadas a seguir ao arquivo build.gradle da sua 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'
  • adaptativo: elementos básicos de baixo nível, 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.

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 de 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 exibido. Como esse tipo é parcelable, o estado pode ser salvo e restaurado pelo navegador para processam automaticamente as mudanças de configuração. O BackHandler oferece suporte à navegação de volta usando o gesto "Voltar" do sistema; ou . O comportamento esperado do botão "Voltar" para um ListDetailPaneScaffold depende do tamanho da janela e do valor atual do scaffold. Se o ListDetailPaneScaffold puder voltar ao estado atual, o canNavigateBack() será true, ativando o BackHandler.

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

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

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

  4. Forneça a implementação do painel de lista para o ListDetailPaneScaffold. Use AnimatedPane para aplicar as animações padrão do painel 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 em ListDetailPaneScaffold. Quando a navegação for concluída, currentDestination vai conter o painel para o qual o app navegou, incluindo o conteúdo exibido no painel. A propriedade content é do mesmo tipo especificado na chamada de recordação original (MyItem neste exemplo). Assim, você também pode acessar a propriedade para qualquer dado que precise mostrar.

    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)
            }
        }
    },
)