Создайте подробный макет списка

List-detail — это шаблон пользовательского интерфейса, который состоит из макета с двумя панелями, где одна панель представляет список элементов, а другая панель отображает сведения об элементах, выбранных из списка.

Этот шаблон особенно полезен для приложений, которые предоставляют подробную информацию об элементах больших коллекций, например, для почтового клиента, который имеет список электронных писем и подробное содержимое каждого сообщения электронной почты. List-detail также можно использовать для менее важных путей, таких как разделение настроек приложения на список категорий с настройками для каждой категории на панели сведений.

Реализуйте шаблон пользовательского интерфейса с помощью ListDetailPaneScaffold

ListDetailPaneScaffold — это составной компонент, который упрощает реализацию шаблона подробностей списка в вашем приложении. Структура подробного списка может состоять из трех панелей: панели списка, панели подробностей и дополнительной панели. Эшаффолд выполняет расчеты экранного пространства. Если доступен достаточный размер экрана, панель сведений отображается рядом с панелью списка. На экранах небольших размеров scaffold автоматически переключается на полноэкранное отображение либо списка, либо панели подробностей.

Панель сведений, отображаемая рядом со страницей списка.
Рис. 1. Если доступен достаточный размер экрана, панель сведений отображается рядом с панелью списка.
После выбора элемента панель сведений занимает весь экран.
Рис. 2. Когда размер экрана ограничен, панель сведений (поскольку элемент выбран) занимает все пространство.

Объявить зависимости

ListDetailPaneScaffold — часть библиотеки адаптивной компоновки Material 3 .

Добавьте следующие три связанные зависимости в файл build.gradle вашего приложения или модуля:

Котлин


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

классный


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

  • адаптивный — низкоуровневые строительные блоки, такие как HingeInfo и Posture
  • Adaptive-layout — Адаптивные макеты, такие как ListDetailPaneScaffold и SupportingPaneScaffold
  • Adaptive-navigation — Составные элементы для навигации внутри и между панелями

Основное использование

Реализуйте ListDetailPaneScaffold следующим образом:

  1. Используйте класс, представляющий выбираемое содержимое. Этот класс должен быть Parcelable , чтобы поддерживать сохранение и восстановление выбранного элемента списка. Используйте плагин kotlin-parcelize для генерации кода.

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

  2. Создайте ThreePaneScaffoldNavigator с помощью rememberListDetailPaneScaffoldNavigator и добавьте BackHandler . Этот навигатор используется для перемещения между списком, деталями и дополнительными панелями. Объявляя универсальный тип, навигатор также отслеживает состояние scaffold (то есть, какой MyItem отображается). Поскольку этот тип можно разделить, состояние может быть сохранено и восстановлено навигатором для автоматической обработки изменений конфигурации. BackHandler обеспечивает поддержку перехода назад с помощью системного жеста или кнопки. Ожидаемое поведение кнопки «Назад» для ListDetailPaneScaffold зависит от размера окна и текущего значения шаблона. Если ListDetailPaneScaffold поддерживает возврат к текущему состоянию, тогда canNavigateBack() имеет true , что позволяет BackHandler .

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

  3. Передайте scaffoldState из navigator в составной элемент ListDetailPaneScaffold .

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

  4. Предоставьте реализацию панели списка в ListDetailPaneScaffold . Используйте AnimatedPane , чтобы применить анимацию панели по умолчанию во время навигации. Затем используйте ThreePaneScaffoldNavigator , чтобы перейти к панели сведений ListDetailPaneScaffoldRole.Detail и отобразить переданный элемент.

    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. Включите реализацию области подробностей в ListDetailPaneScaffold . После завершения навигации currentDestination содержит панель, к которой перешло ваше приложение, включая содержимое, отображаемое на панели. Свойство content имеет тот же тип, который указан в исходном вызове запоминания (в этом примере MyItem ), поэтому вы также можете получить доступ к свойству для любых данных, которые вам нужно отобразить.

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

После реализации описанных выше шагов ваш код должен выглядеть примерно так:

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