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

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

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

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

Реализуйте шаблон List-Detail с помощью NavigableListDetailPaneScaffold

NavigableListDetailPaneScaffold — это составной элемент, который упрощает реализацию макета списка со сведениями в Jetpack Compose. Он оборачивает ListDetailPaneScaffold и добавляет встроенную навигацию и прогнозирующую обратную анимацию.

Структура подробного списка поддерживает до трех панелей:

  1. Панель списка : отображает коллекцию элементов.
  2. Панель сведений : показывает сведения о выбранном элементе.
  3. Дополнительная панель ( необязательно ) : при необходимости предоставляет дополнительный контекст.

Леса адаптируются в зависимости от размера окна:

  • В больших окнах панели списка и сведений отображаются рядом.
  • В маленьких окнах одновременно видна только одна панель, которая переключается по мере навигации пользователя.

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

NavigableListDetailPaneScaffold — часть библиотеки адаптивной навигации 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: Composables для навигации внутри и между панелями, а также адаптивные макеты, поддерживающие навигацию по умолчанию, такие как NavigableListDetailPaneScaffold и NavigableSupportingPaneScaffold

Убедитесь, что ваш проект включает Compose-material3-adaptive версии 1.1.0-beta1 или выше.

Включите интеллектуальный жест назад

Чтобы включить интеллектуальную анимацию назад в Android 15 или более ранней версии, вам необходимо включить поддержку прогнозируемого жеста назад. Чтобы принять участие, добавьте android:enableOnBackInvokedCallback="true" в тег <application> или отдельные теги <activity> в файле AndroidManifest.xml . Дополнительную информацию см. в разделе «Включение интеллектуального жеста назад» .

Если ваше приложение ориентировано на Android 16 (уровень API 36) или выше, функция прогнозирования включена по умолчанию.

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

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

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

Этот навигатор используется для перемещения между списком, деталями и дополнительными панелями. Объявляя универсальный тип, навигатор также отслеживает состояние scaffold (то есть, какой MyItem отображается). Поскольку этот тип можно разделить, состояние может быть сохранено и восстановлено навигатором для автоматической обработки изменений конфигурации.

  1. Передайте навигатор составному элементу NavigableListDetailPaneScaffold .

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

  3. Включите реализацию области подробностей в NavigableListDetailPaneScaffold .

Когда навигация завершена, currentDestination содержит панель, к которой перешло ваше приложение, включая содержимое, отображаемое на панели. Свойство contentKey имеет тот же тип, что указан в исходном вызове, поэтому вы можете получить доступ к любым данным, которые вам нужно отобразить.

  1. При необходимости измените defaultBackBehavior в NavigableListDetailPaneScaffold . По умолчанию NavigableListDetailPaneScaffold использует PopUntilScaffoldValueChange для defaultBackBehavior .

Если вашему приложению требуется другой шаблон обратной навигации, вы можете переопределить это поведение, указав другой параметр BackNavigationBehavior .

BackNavigationBehavior поведения

В следующем разделе используется пример почтового приложения со списком электронных писем на одной панели и подробным представлением на другой.

Такое поведение фокусируется на изменениях в общей структуре макета. В настройке с несколькими панелями изменение содержимого электронной почты на подробной панели не меняет базовую структуру макета. Таким образом, кнопка «Назад» может выйти из приложения или текущего графа навигации, поскольку нет изменения макета, к которому можно было бы вернуться в текущем контексте. В макете с одной панелью нажатие «Назад» пропустит изменения содержимого в подробном представлении и вернется к представлению списка, поскольку это представляет собой явное изменение макета.

Рассмотрим следующие примеры:

  • Несколько панелей: вы просматриваете электронное письмо (пункт 1) на панели сведений. При нажатии на другое электронное письмо (пункт 2) панель сведений обновляется, но панели списка и сведений остаются видимыми. Нажатие «Назад» может привести к выходу из приложения или текущего процесса навигации.
  • Одна панель: вы просматриваете элемент 1, затем элемент 2, нажатие кнопки «Назад» вернет вас прямо на панель списка адресов электронной почты.

Используйте это, если вы хотите, чтобы пользователи воспринимали отдельные переходы макета при каждом обратном действии.

Изменение значения навигации.
PopUntilContentChange

Такое поведение определяет приоритет отображаемого контента. Если вы просмотрите элемент 1, а затем элемент 2, нажатие кнопки «Назад» приведет к возврату к элементу 1 независимо от макета.

Рассмотрим следующие примеры:

  • Многопанельный режим: вы просматриваете элемент 1 на панели сведений, затем щелкните элемент 2 в списке. Панель сведений обновится. Нажатие назад вернет панель сведений к элементу 1.
  • Однопанельный: происходит то же самое возвращение содержимого.

Используйте это, когда ваш пользователь ожидает вернуться к ранее просмотренному контенту с помощью обратного действия.

переход между двумя панелями подробностей
PopUntilCurrentDestinationChange

Такое поведение выталкивает задний стек до тех пор, пока не изменится текущий пункт назначения навигации . Это в равной степени относится к макетам с одной и несколькими панелями.

Рассмотрим следующие примеры:

Независимо от того, используете ли вы макет с одной или несколькими панелями, нажатие кнопки «Назад» всегда перемещает фокус с выделенного элемента навигации на предыдущий пункт назначения. В нашем почтовом приложении это означает, что визуальное обозначение выбранной панели сместится.

Используйте это, когда поддержание четкой визуальной индикации текущей навигации имеет решающее значение для взаимодействия с пользователем.

навигация между панелями подробностей и списками
PopLatest

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

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

val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
val scope = rememberCoroutineScope()

NavigableListDetailPaneScaffold(
    navigator = scaffoldNavigator,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    scope.launch {
                        scaffoldNavigator.navigateTo(
                            ListDetailPaneScaffoldRole.Detail,
                            item
                        )
                    }
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            scaffoldNavigator.currentDestination?.contentKey?.let {
                MyDetails(it)
            }
        }
    },
)