辅助窗格布局使用户的注意力集中在应用的主要内容上,同时显示相关的辅助信息。例如,主窗格可能显示电影的详细信息,而辅助窗格则列出类似的电影、同一导演的作品或同一演员出演的作品。
如需了解更多详细信息,请参阅 Material 3 辅助窗格指南。
使用 NavigableSupportingPaneScaffold 实现辅助窗格
NavigableSupportingPaneScaffold
是一个可组合函数,可简化在 Jetpack Compose 中实现辅助窗格布局的过程。它封装了 SupportingPaneScaffold
,并添加了内置导航和预测性返回处理功能。
辅助窗格 scaffold 最多支持三个窗格
- 主窗格:显示主要内容。
- 辅助窗格:提供与主窗格相关的额外上下文或工具。
- 额外窗格(可选):在需要时用于补充内容。
scaffold 根据窗口大小进行调整
- 在大窗口中,主窗格和辅助窗格并排显示。
在小窗口中,一次只能显示一个窗格,用户导航时会进行切换。
图 1. 辅助窗格布局。
添加依赖项
NavigableSupportingPaneScaffold
是 Material 3 自适应布局库的一部分。
将以下三个相关依赖项添加到您的应用或模块的 build.gradle
文件中
Kotlin
implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")
Groovy
implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
adaptive-layout:自适应布局,例如
ListDetailPaneScaffold
和SupportingPaneScaffold
adaptive-navigation:用于在窗格内和窗格之间导航的可组合项,以及默认支持导航的自适应布局,例如
NavigableListDetailPaneScaffold
和NavigableSupportingPaneScaffold
请确保您的项目包含 compose-material3-adaptive 1.1.0-beta1 版或更高版本。
选择启用预测性返回手势
要在 Android 15 或更低版本中启用预测性返回动画,您必须选择支持预测性返回手势。要选择启用,请在 AndroidManifest.xml
文件中,将 android:enableOnBackInvokedCallback="true"
添加到 <application>
标记或单个 <activity>
标记。
一旦您的应用以 Android 16(API 级别 36)或更高版本为目标,预测性返回将默认启用。
创建导航器
在小窗口中,一次只显示一个窗格,因此请使用 ThreePaneScaffoldNavigator
在窗格之间移动。使用 rememberSupportingPaneScaffoldNavigator
创建导航器实例。
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
将导航器传递给 scaffold
scaffold 需要一个 ThreePaneScaffoldNavigator
,它是一个表示 scaffold 状态的接口,ThreePaneScaffoldValue
和 PaneScaffoldDirective
。
NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, )
主窗格和辅助窗格是包含内容的 composable。使用 AnimatedPane
在导航期间应用默认的窗格动画。使用 scaffold 值检查辅助窗格是否已隐藏;如果已隐藏,则显示一个按钮,该按钮调用 navigateTo(SupportingPaneScaffoldRole.Supporting)
以显示辅助窗格。
以下是 scaffold 的完整实现
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
的使用(与上一节中 scaffold 的完整实现进行比较)
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() }, )
如果您需要对 scaffold 的特定方面进行更多控制,请考虑使用 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() }, )