“列表-详情”是一种界面模式,由双窗格布局组成,其中一个窗格显示项目列表,另一个窗格显示从列表中选择的项目的详细信息。
此模式特别适用于提供有关大型集合元素的深入信息的应用,例如,具有电子邮件列表和每封电子邮件的详细内容的邮件客户端。“列表- 详情”也可用于不太重要的路径,例如将应用偏好设置划分为类别列表,并在详情窗格中显示每个类别的偏好设置。
使用 NavigableListDetailPaneScaffold 实现“列表-详情”模式
NavigableListDetailPaneScaffold 是一个可组合项,可简化在 Jetpack Compose
中实现“列表-详情”布局的过程。它封装了 ListDetailPaneScaffold,并添加了内置导航和预测性返回动画。
“列表-详情”脚手架最多支持三个窗格:
- 列表窗格:显示项目集合。
- 详情窗格:显示所选项目的详细信息。
- 额外窗格(可选) :在需要时提供其他背景信息。
脚手架会根据窗口大小进行调整:
- 在大型窗口中,列表窗格和详情窗格并排显示。
- 在小型窗口中,一次只能显示一个窗格,并且会随着用户导航而切换。
声明依赖项
NavigableListDetailPaneScaffold 是 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:低级别构建块,例如
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)或更高版本为目标平台,预测性返回功能就会默认启用。
基本用法
按如下方式实现 NavigableListDetailPaneScaffold:
- 使用表示所选内容的类。使用
Parcelable类来支持保存和恢复所选列表项。使用 kotlin-parcelize 插件为您生成代码。 - 使用
rememberListDetailPaneScaffoldNavigator创建ThreePaneScaffoldNavigator。
此导航器用于在列表窗格、详情窗格和额外窗格之间移动。通过声明泛型,导航器还会跟踪脚手架的状态(即正在显示哪个
MyItem)。由于此类型是可打包的,因此导航器可以保存和恢复状态,以自动处理配置更改。
将导航器传递给
NavigableListDetailPaneScaffold可组合项。向
NavigableListDetailPaneScaffold提供列表窗格实现。使用AnimatedPane在导航期间应用 默认窗格动画。然后使用ThreePaneScaffoldNavigator导航到“详细信息”窗格ListDetailPaneScaffoldRole.Detail,并显示传递的项目。在
NavigableListDetailPaneScaffold中添加详情窗格实现。
导航完成后,currentDestination 会包含应用导航到的窗格,包括窗格中显示的内容。contentKey
属性与原始调用中指定的类型相同,因此您可以访问需要显示的任何数据。
- (可选)更改
NavigableListDetailPaneScaffold中的defaultBackBehavior。默认情况下,NavigableListDetailPaneScaffold会将PopUntilScaffoldValueChange用于defaultBackBehavior。
如果您的应用需要不同的返回导航模式,您可以通过指定另一个 BackNavigationBehavior 选项来替换此行为。
BackNavigationBehavior 选项
以下部分以电子邮件应用为例,其中一个窗格中包含电子邮件列表,另一个窗格中包含详细视图。
PopUntilScaffoldValueChange(默认值,在大多数情况下建议使用)
此行为侧重于对整体布局结构的更改。在多窗格设置中,更改详细窗格中的电子邮件内容不会改变底层布局结构。因此,返回按钮可能会退出应用或当前导航图,因为当前上下文中没有可恢复的布局更改。在单窗格布局中,按返回键会跳过详细视图中的内容更改并返回到列表视图,因为这表示明确的布局更改。
请参考以下示例:
- 多窗格 :您正在详情窗格中查看电子邮件(项目 1)。点击另一封电子邮件(项目 2)会更新详情窗格,但列表窗格和详情窗格仍可见。按返回键可能会退出应用或当前导航流程。
- 单窗格 :您查看项目 1,然后查看项目 2,按返回键会直接返回到邮箱名单窗格。
如果您希望用户在每次返回操作时都感知到不同的布局转换,请使用此选项。
PopUntilContentChange
此行为优先考虑显示的内容。如果您先查看项目 1,然后查看项目 2,按返回键会恢复到项目 1,无论布局如何。
请参考以下示例:
- 多窗格 :您在详情窗格中查看项目 1,然后在列表中点击项目 2。详情窗格会更新。按返回键会将详情窗格恢复为项目 1。
- 单窗格 :发生相同的内容恢复。
如果用户希望通过返回操作返回到之前查看的内容,请使用此选项。
PopUntilCurrentDestinationChange
此行为会弹出返回堆栈,直到当前导航目的地发生更改。 这同样适用于单窗格和多窗格布局。
请参考以下示例:
无论您使用的是单窗格布局还是多窗格布局,按返回键始终会将焦点从突出显示的导航元素移到上一个目的地。在我们的电子邮件应用中,这意味着所选窗格的视觉指示会发生变化。
如果保持当前导航的清晰视觉指示对于用户体验至关重要,请使用此选项。
PopLatest
此选项仅从返回堆栈中移除最近的目的地。使用此选项进行返回导航,而无需跳过中间状态。
执行完这些步骤后,您的代码应如下所示:
NavigableListDetailPaneScaffold( navigator = navigator, listPane = { AnimatedPane { ListContent( words = sampleWords, selectionState = navigator.currentDestination?.contentKey?.let { SelectionVisibilityState.ShowSelection(it) } ?: SelectionVisibilityState.NoSelection, onWordClick = { word -> scope.launch { navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word) } }, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout ) } }, detailPane = { AnimatedPane { DetailContent( definedWord = navigator.currentDestination?.contentKey, animatedVisibilityScope = this@AnimatedPane, sharedTransitionScope = this@SharedTransitionLayout, onClosePane = { scope.launch { navigator.navigateBack( backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange ) } } ) } }