列表-详情是一种 UI 模式,它由一个双窗格布局组成,其中一个窗格显示项目列表,另一个窗格显示从列表中选择的项目的详细信息。
这种模式对于提供大型集合元素的深入信息的应用程序特别有用,例如,一个电子邮件客户端,它包含一个电子邮件列表以及每个电子邮件消息的详细内容。列表-详情模式也可用于不太重要的路径,例如将应用程序首选项划分为类别列表,并在详情窗格中显示每个类别的首选项。
使用 ListDetailPaneScaffold
实现 UI 模式
ListDetailPaneScaffold
是一个可组合项,它简化了在您的应用中实现列表-详情模式的过程。列表-详情框架最多可以包含三个窗格:列表窗格、详情窗格和一个可选的额外窗格。该框架负责处理屏幕空间的计算。当有足够的屏幕空间时,详情窗格会与列表窗格一起显示。在小屏幕尺寸下,框架会自动切换为全屏显示列表或详情窗格。
声明依赖项
ListDetailPaneScaffold
是 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'
- 自适应 — 低级构建块,例如
HingeInfo
和Posture
- 自适应布局 — 自适应布局,例如
ListDetailPaneScaffold
和SupportingPaneScaffold
- 自适应导航 — 用于在窗格内和窗格之间导航的可组合项
基本用法
按如下方式实现 ListDetailPaneScaffold
使用一个表示要选择的内容的类。此类应为
Parcelable
以支持保存和恢复选定的列表项。使用 kotlin-parcelize 插件 为您生成代码。@Parcelize class MyItem(val id: Int) : Parcelable
使用
rememberListDetailPaneScaffoldNavigator
创建一个ThreePaneScaffoldNavigator
并添加一个BackHandler
。此导航器用于在列表、详情和额外窗格之间移动。通过声明一个泛型类型,导航器还会跟踪框架的状态(即,正在显示哪个MyItem
)。由于此类型是可打包的,因此导航器可以保存和恢复状态以自动处理配置更改。BackHandler
提供了使用系统后退手势或按钮进行后退导航的支持。ListDetailPaneScaffold
的后退按钮的预期行为取决于窗口大小和当前框架值。如果ListDetailPaneScaffold
可以支持使用当前状态后退,则canNavigateBack()
为true
,从而启用BackHandler
。val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() }
将
navigator
中的scaffoldState
传递给ListDetailPaneScaffold
可组合项。ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, // ... )
将您的列表窗格实现提供给
ListDetailPaneScaffold
。使用AnimatedPane
在导航期间应用默认的窗格动画。然后使用ThreePaneScaffoldNavigator
导航到详情窗格ListDetailPaneScaffoldRole.Detail
并显示传递的项目。ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { MyList( onItemClick = { item -> // Navigate to the detail pane with the passed item navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) } ) } }, // ... )
在
ListDetailPaneScaffold
中包含您的详情窗格实现。导航完成后,currentDestination
包含您的应用已导航到的窗格,包括在窗格中显示的内容。content
属性与原始 remember 调用中指定的类型相同(在本例中为MyItem
),因此您还可以访问该属性以获取需要显示的任何数据。ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = // ... detailPane = { AnimatedPane { navigator.currentDestination?.content?.let { MyDetails(it) } } }, )
完成上述步骤后,您的代码应类似于以下内容
val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane { MyList( onItemClick = { item -> // Navigate to the detail pane with the passed item navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item) }, ) } }, detailPane = { AnimatedPane { // Show the detail pane content if selected item is available navigator.currentDestination?.content?.let { MyDetails(it) } } }, )