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

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

Более подробную информацию см. в рекомендациях по вспомогательной панели Материала 3 .

Реализуйте вспомогательную панель с помощью NavigableSupportingPaneScaffold.

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

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

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

Чтобы включить интеллектуальную анимацию назад в Android 15 или более ранней версии, вам необходимо включить поддержку прогнозируемого жеста назад. Чтобы принять участие, добавьте android:enableOnBackInvokedCallback="true" в тег <application> [или 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

Присоедините прогнозирующий обратный обработчик, который принимает экземпляр навигатора скаффолда, и укажите 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() },
)