Создание вспомогательного макета панели

Макет вспомогательных панелей позволяет пользователю сосредоточиться на основном контенте приложения, одновременно отображая важную дополнительную информацию. Например, на главной панели может отображаться информация о фильме, а на вспомогательной — список похожих фильмов, фильмов того же режиссёра или работ с теми же актёрами.

Более подробную информацию см. в руководстве по вспомогательным панелям Material 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 и Posture

  • adaptive-layout : адаптивные макеты, такие как ListDetailPaneScaffold и SupportingPaneScaffold

  • adaptive-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) , для отображения вспомогательной панели.

Вот полная реализация каркаса:

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

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()) {
            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(
    modifier: Modifier = Modifier,
) {
    AnimatedPane(modifier = modifier.safeContentPadding()) {
        // Supporting pane content
        Text("This is the 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() },
)

Если вам нужен больший контроль над отдельными аспектами скаффолда, рассмотрите возможность использования 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() },
)