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

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

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

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

Реализуйте шаблон «Список-Подробности» с помощью 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
  • адаптивная компоновка: адаптивные компоновки, такие как ListDetailPaneScaffold и SupportingPaneScaffold
  • адаптивная навигация: компонуемые элементы для навигации внутри панелей и между ними, а также адаптивные макеты, которые поддерживают навигацию по умолчанию, такие как 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 поведения

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

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

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

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

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

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

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

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

  • Multi-Pane: Вы просматриваете Item 1 в панели сведений, затем нажимаете Item 2 в списке. Панель сведений обновляется. Нажатие кнопки «Назад» восстановит панель сведений до Item 1.
  • Однопанельный режим: происходит тот же возврат содержимого.

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

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

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

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

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

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

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

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

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

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