Вспомогательная панель позволяет пользователю сосредоточиться на основном содержимом приложения, одновременно отображая необходимую дополнительную информацию. Например, в основной панели может отображаться информация о фильме, а во вспомогательной — список похожих фильмов, фильмов того же режиссера или работ с участием тех же актеров.
Более подробную информацию см. в руководстве по использованию вспомогательной панели «Материал 3» .
Реализуйте вспомогательную панель с помощью каркаса.
NavigableSupportingPaneScaffold — это компонент, упрощающий реализацию макета вспомогательных панелей в Jetpack Compose. Он является оберткой SupportingPaneScaffold и добавляет встроенную навигацию и предиктивную обработку возврата.
Опорный каркас для стеклянных панелей поддерживает до трех стекол:
- Главная панель : Отображает основное содержимое.
- Вспомогательная панель : Предоставляет дополнительный контекст или инструменты, связанные с основной панелью.
- Дополнительная панель (необязательно) : используется для размещения дополнительного контента при необходимости.
Конструкция адаптируется в зависимости от размера окна:
- В больших окнах основное и вспомогательные стекла расположены рядом друг с другом.
В небольших окнах одновременно видна только одна панель, переключение между которыми происходит по мере перемещения пользователя.

Рисунок 1. Схема расположения вспомогательных панелей.
Добавить зависимости
NavigableSupportingPaneScaffold является частью библиотеки адаптивной компоновки 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иPostureadaptive-layout : Адаптивные макеты, такие как
ListDetailPaneScaffoldиSupportingPaneScaffoldadaptive-navigation : Компоненты для навигации внутри и между панелями, а также адаптивные макеты, поддерживающие навигацию по умолчанию, такие как
NavigableListDetailPaneScaffoldиNavigableSupportingPaneScaffold
Убедитесь, что ваш проект включает compose-material3-adaptive версии 1.1.0-beta1 или выше.
Включите функцию автоматического ввода жеста "назад"
Чтобы включить анимацию «Назад» с функцией прогнозирования в Android 15 или более ранних версиях, необходимо включить поддержку жеста «Назад». Для этого добавьте android:enableOnBackInvokedCallback="true" в тег ` <application> или отдельные теги <activity> ` в файле AndroidManifest.xml .
Если ваше приложение ориентировано на Android 16 (уровень API 36) или выше, функция предиктивного ответа "Назад" включается по умолчанию.
Создать навигатор
В небольших окнах одновременно отображается только одна панель, поэтому используйте ThreePaneScaffoldNavigator для перемещения между панелями. Создайте экземпляр навигатора с помощью rememberSupportingPaneScaffoldNavigator .
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
Передайте штурмана на эшафот.
Для работы с генератором кода требуется интерфейс ThreePaneScaffoldNavigator , представляющий состояние генератора кода, ThreePaneScaffoldValue и PaneScaffoldDirective .
NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, )
Основная панель и вспомогательная панель представляют собой составные элементы, содержащие ваш контент. Используйте AnimatedPane для применения анимации панелей по умолчанию во время навигации. Используйте значение scaffold, чтобы проверить, скрыта ли вспомогательная панель; если да, отобразите кнопку, которая вызывает navigateTo(SupportingPaneScaffoldRole.Supporting) для отображения вспомогательной панели.
Для больших экранов используйте метод ThreePaneScaffoldNavigator.navigateBack() для закрытия вспомогательной панели, передав константу BackNavigationBehavior.PopUntilScaffoldValueChange . Вызов этого метода принудительно перестраивает NavigableSupportingPaneScaffold . Во время перестройки проверьте свойство ThreePaneScaffoldNavigator.currentDestination , чтобы определить, следует ли отображать вспомогательную панель.
Вот полная реализация шаблона:
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() val backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { AnimatedPane( modifier = Modifier .safeContentPadding() .background(Color.Red) ) { if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden) { Button( modifier = Modifier .wrapContentSize(), onClick = { scope.launch { scaffoldNavigator.navigateTo(SupportingPaneScaffoldRole.Supporting) } } ) { Text("Show supporting pane") } } else { Text("Supporting pane is shown") } } }, supportingPane = { AnimatedPane(modifier = Modifier.safeContentPadding()) { Column { // Allow users to dismiss the supporting pane. Use back navigation to // hide an expanded supporting pane. if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) { // Material design principles promote the usage of a right-aligned // close (X) button. IconButton( modifier = Modifier.align(Alignment.End).padding(16.dp), onClick = { scope.launch { scaffoldNavigator.navigateBack(backNavigationBehavior) } } ) { Icon(Icons.Default.Close, contentDescription = "Close") } } Text("Supporting pane") } } } )
Извлечь составные элементы панели
Выделите отдельные панели из SupportingPaneScaffold в отдельные компонуемые объекты, чтобы сделать их многоразовыми и пригодными для тестирования. Используйте ThreePaneScaffoldScope для доступа к AnimatedPane если вам нужны анимации по умолчанию:
@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun ThreePaneScaffoldPaneScope.MainPane( shouldShowSupportingPaneButton: Boolean, onNavigateToSupportingPane: () -> Unit, modifier: Modifier = Modifier, ) { AnimatedPane( modifier = modifier.safeContentPadding() ) { // Main pane content if (shouldShowSupportingPaneButton) { Button(onClick = onNavigateToSupportingPane) { Text("Show supporting pane") } } else { Text("Supporting pane is shown") } } } @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun ThreePaneScaffoldPaneScope.SupportingPane( scaffoldNavigator: ThreePaneScaffoldNavigator<Any>, modifier: Modifier = Modifier, backNavigationBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange, ) { val scope = rememberCoroutineScope() AnimatedPane(modifier = Modifier.safeContentPadding()) { Column { // Allow users to dismiss the supporting pane. Use back navigation to // hide an expanded supporting pane. if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) { // Material design principles promote the usage of a right-aligned // close (X) button. IconButton( modifier = modifier.align(Alignment.End).padding(16.dp), onClick = { scope.launch { scaffoldNavigator.navigateBack(backNavigationBehavior) } } ) { Icon(Icons.Default.Close, contentDescription = "Close") } } Text("Supporting pane") } } }
Выделение панелей в составные элементы упрощает использование SupportingPaneScaffold (сравните приведенный ниже пример с полной реализацией этого элемента в предыдущем разделе):
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { MainPane( shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, onNavigateToSupportingPane = { scope.launch { scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) } } ) }, supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) }, )
Если вам требуется больший контроль над определенными аспектами структуры проекта, рассмотрите возможность использования SupportingPaneScaffold вместо NavigableSupportingPaneScaffold . Этот метод принимает отдельно PaneScaffoldDirective и ThreePaneScaffoldValue или ThreePaneScaffoldState . Такая гибкость позволяет реализовать собственную логику для интервалов между панелями и определить, сколько панелей должно отображаться одновременно. Вы также можете включить поддержку предиктивной отправки, добавив ThreePaneScaffoldPredictiveBackHandler .
Добавить ThreePaneScaffoldPredictiveBackHandler
Прикрепите обработчик предсказания возврата, который принимает экземпляр навигатора Scaffold и указывает backBehavior . Это определяет, как пункты назначения удаляются из стека возврата во время навигации назад. Затем передайте scaffoldDirective и scaffoldState в SupportingPaneScaffold . Используйте перегрузку, которая принимает ThreePaneScaffoldState , передавая scaffoldNavigator.scaffoldState .
Определите основную и вспомогательные панели в классе SupportingPaneScaffold . Используйте AnimatedPane для анимации панелей по умолчанию.
После выполнения этих шагов ваш код должен выглядеть примерно так:
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() ThreePaneScaffoldPredictiveBackHandler( navigator = scaffoldNavigator, backBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange ) SupportingPaneScaffold( directive = scaffoldNavigator.scaffoldDirective, scaffoldState = scaffoldNavigator.scaffoldState, mainPane = { MainPane( shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, onNavigateToSupportingPane = { scope.launch { scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) } } ) }, supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) }, )