Compose – List / Detail: Basics实现
Compose – List / Detail: Basics实现
在androidx中有SlidingPanelLayout可以实现折叠屏的列表详情功能,但在Compose 中还没有官方的实现,那么下面我们用Compose做一些实现。
List / Detail
我们追求的基本行为是当 UI 具有项列表时。当用户点击列表中的项目时,我们会在详细信息视图中显示详细信息。在较大的屏幕上,可能有足够的空间并排显示列表和详细信息视图。但是,在较小的设备上,点击项目可能会将列表视图替换为详细信息视图,并且返回返回。
我们可以在较旧的基于视图的 UI 上执行此操作,方法是为不同的屏幕尺寸提供不同的布局。最近,可以处理繁重的工作。SlidingPaneLayout
要使用 Compose 执行此操作,让我们首先看一下列表和详细信息可组合项:
@Composable
fun MyList(list: List, onSelectionChange: (String) -> Unit) {LazyColumn {for (entry in list) {item {Row(Modifier.fillMaxWidth().clickable { onSelectionChange(entry) }.padding(horizontal = 16.dp, vertical = 8.dp)) {Text(text = entry)}}}}
}@Composable
fun Detail(text: String) {Text(text = text)
}
我故意使这些尽可能简单。这是为了使代码易于理解。
MyList()使用 list作为参数提供的项列表,选择操作由选择器接口参数处理。 仅显示一段文本 - 稍后将内联LazyColumnDetail() 。
创建简单的 DSL
为了方便以后的事情,让我们创建一个简单的DSL,它将提供一种流畅的方式来声明列表和详细信息UI:
@Immutable
interface TwoPaneScope {val list: @Composable (List, (T) -> Unit) -> Unitval detail: @Composable (T) -> Unit@Composablefun List(newList: @Composable (List, (T) -> Unit) -> Unit)@Composablefun Detail(newDetail: @Composable (T) -> Unit)
}private class TwoPaneScopeImpl(val items: List
) : TwoPaneScope {override var list: @Composable (List, (T) -> Unit) -> Unit = { _, _ -> }private setoverride var detail: @Composable (T) -> Unit = {}private set@Composableoverride fun List(newList: @Composable (List, (T) -> Unit) -> Unit) {list = newList}@Composableoverride fun Detail(newDetail: @Composable (T) -> Unit) {detail = newDetail}
}
这提供了一个范围,我们可以在其中声明列表和详细 UI。稍后我们将介绍其实现。现在,我们需要知道的是,我们可以像这样声明 UI:
ListDetailLayout((1..10).map { index -> "Item $index" },LocalConfiguration.current
) {List { list, onSelectionChange ->MyList(list, onSelectionChange)}Detail { text ->Text(text = text)}
}
稍后我们将看到如何访问 和 块的 UI 定义ListDetail
拆分布局
拆分布局(即并排布局)相对容易实现:
@Composable
private fun SplitLayout(twoPaneScope: TwoPaneScopeImpl,selected: String?,onSelectionChange: (String) -> Unit
) {Row(Modifier.fillMaxWidth()) {Box(modifier = Modifier.weight(1f)) {twoPaneScope.list(twoPaneScope.items, onSelectionChange)}Box(modifier = Modifier.weight(1f)) {twoPaneScope.detail(selected ?: "Nothing selected")}}
}
在这里,我们将选定的状态作为参数和 lambda 传入,以处理选择更改。保持我们的可组合物无状态是一种很好的做法,因为它可以使它们不那么容易出错,并且更容易测试。
我们从 获取列表和详细 UItwoPaneScope
对于列表 UI,我们将列表指定为第一个参数,将选择更改处理程序指定为第二个参数。
对于详细信息 UI,我们将文本设置为参数的值。selected
我们使用 .我在这里使用了相等的权重将屏幕分成两半。但是,为了满足不同的要求而改变这一点是微不足道的Row
当用户点击列表项时,文本将显示在右侧窗格中:

双页布局
实现两页布局略有不同,因为我们需要显示列表 UI 或详细信息 UI,具体取决于我们是否有选定的项目
@Composable
private fun TwoPageLayout(twoPaneScope: TwoPaneScopeImpl,selected: String?,onSelectionChange: (String) -> Unit
) {Box(modifier = Modifier.fillMaxWidth()) {if (selected == null) {twoPaneScope.list(twoPaneScope.items, onSelectionChange)} else {twoPaneScope.detail(selected)}}
}
我们再次从 UI 细节中获取并将它们连接到和以前。这里真正的区别在于,我们显示列表 UI 或详细信息 UI 取决于是否为twoPaneScope selection onSelectionChange selection=null
这给出了我们所追求的基本行为:

为了使代码简单易懂,我没有包含任何导航动画。但这肯定是我在真正使用它时希望添加的内容。
导航
不同详细信息项目的选择将由Navigation库处理。在这个简单的示例中,将有一个路由:NavGraph
https://developer.android.com/jetpack/compose/navigation
private object NavGraph {sealed class Route(val route: String) {object Detail : Route("detail/{selected}") {fun navigateRoute(selected: String?) = "detail/$selected"}}
}
此路由采用将在详细信息 UI 中显示的字符串的参数。导航到此将提供适当的参数。
到目前为止,我们所看到的组件与NavGraph的使用完全无关。这是非常刻意的。这意味着和/或仅关注不同的布局类型。在处理配置更改时,让它们无状态也将有助于将导航逻辑提升到更高的水平将有助于实现这一目标SplitLayoutTwoPageLayout。
列表详细布局
现在我们已经实现了基本的行为模式,我们需要添加何时使用每种模式的逻辑。这在Compose中实际上非常简单:
@Composable
@Suppress("MagicNumber")
fun ListDetailLayout(list: List,configuration: Configuration,scope: @Composable TwoPaneScope.() -> Unit
) {val isSmallScreen = configuration.smallestScreenWidthDp < 580val navController = rememberNavController()val twoPaneScope = TwoPaneScopeImpl(list).apply { scope() }NavHost(navController = navController, startDestination = NavGraph.Route.Detail.route) {composable(NavGraph.Route.Detail.route) { navBackStackEntry ->val selected = navBackStackEntry.arguments?.getString("selected")if (isSmallScreen) {TwoPageLayout(twoPaneScope, selected) { selection ->navController.navigate(route = NavGraph.Route.Detail.navigateRoute(selection)) {popUpTo(NavGraph.Route.Detail.navigateRoute(null)) {inclusive = true}}}BackHandler(true) {navController.popBackStack()}} else {SplitLayout(twoPaneScope, selected) { selection ->navController.navigate(route = NavGraph.Route.Detail.navigateRoute(selection)) {popUpTo(NavGraph.Route.Detail.route) {inclusive = true}}}}}}
}
一个实例作为参数传入,我们应用一些简单的逻辑来确定我们是否在小屏幕上运行。Configuration
该对象不是特定于 Compose 的对象,而是资源管理框架用来提供备用资源的对象。因此,我们可以像我们一样利用它。在本例中,我们应用的逻辑与放入布局时的逻辑相同。我们稍后会看看这是从哪里来的Configurationres/layout/sw580
我们在具体实现中调用 lambda,它为我们提供了一个 该 该 是使用在范围内声明的 UI 初始化的。此实例将向下传递到 和 。然后,我们获取一个实例来处理导航。scope TwoPaneScope TwoPaneScopeImpl TwoPageLayout SplitLayout NavController
接下来,我们构造一个包含整个列表详细信息 UI 的内容,无论它是两页布局还是拆分布局。它有一个单一的目的地 - 一个采用当前选择文本的可为空参数的路由NavHostDetail
在可组合目标中,如果我们在小屏幕上运行,我们会发出,否则我们会发出.两个 UI 的导航逻辑略有不同,因为它们使用后退堆栈的方式略有不同TwoPageLayout SplitLayout
每当我们导航到新目的地或进行配置更改时,都会对其进行重构。让导航以这种方式包装整个 UI 将在配置更改后保持 UI 和导航状态。
将组件整合在一起
我们现在可以使用三个参数进行调用:要显示的字符串列表、实例和范围为 的 lambda:DynamicLayoutConfigurationTwoPaneScope
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {ComposeListDetailTheme {Surface(color = MaterialTheme.colors.background) {@Suppress("MagicNumber")ListDetailLayout((1..10).map { index -> "Item $index" },LocalConfiguration.current) {List { list, onSelectionChange ->MyList(list, onSelectionChange)}Detail { text ->Text(text = text)}}}}}}
}
我们通过调用Configuration#LocalConfiguration.current
用户现在将看到不同的 UI,具体取决于窗口大小。这也适用于多窗口 - 当窗口大小越过宽度边界时,UI 会自动切换到580dp
结论
这里没有一个单独的可组合物是特别复杂的。这在很大程度上是设计使然。保持可组合项的小型和集中性使它们更容易组合以创建所需的 UI。例如,仅与要发出的 UI 的逻辑有关。 并对自己的特定行为负全部责任DyanmicLayout TwoPageLayout SplitLayout
虽然这看起来像我们现在想要的行为,但这与 的功能并不完全匹配。在下一篇文章中,我们将看看如何让可折叠设备玩得更好SlidingPaneLayout
文中涉及的源码地址
https://github.com/StylingAndroid/ComposeListDetail/tree/basics
相关文章:
Compose – List / Detail: Basics实现
Compose – List / Detail: Basics实现 在androidx中有SlidingPanelLayout可以实现折叠屏的列表详情功能,但在Compose 中还没有官方的实现,那么下面我们用Compose做一些实现。 List / Detail 我们追求的基本行为是当 UI 具有项列表时。当用户点击列表…...
【Java】TCP网络编程(字节/符流)
文章目录概念TCP网络编程ServerSocketsocket使用区别和原理演示概念 TCP(传输控制协议)是一种面向连接的协议,用于在计算机网络中可靠地传输数据。TCP是Internet协议族中的一个核心协议,它在传输层提供可靠、有序、基于流的传输服…...
Linux之init.d、rc.d文件夹说明
备注:Ubuntu没有rc.d文件夹,原因看问题四 Linux的几个重要文件 rc.d,init.d文件夹的说明 今天在研究mysql的安装的时候,最后一步要创建一个软连接,使得mysql服务可以自启动,代码如下: ln -s…...
数据结构与算法(六):图结构
图是一种比线性表和树更复杂的数据结构,在图中,结点之间的关系是任意的,任意两个数据元素之间都可能相关。图是一种多对多的数据结构。 一、基本概念 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成&#x…...
Kubernetes07:Service
Kubernetes07:Service 1、service存在的意义 因为Pod的IP是不断变化的,所以需要注册service防止pod失联 1)为了防止Pod失联(服务发现) 2、定义一组Pod访问策略(负载均衡) 2、Pod和Service的关系-------通…...
Qt音视频开发18-不同视频打开无缝切换
一、前言 在轮询视频的时候,通常都是需要将之前的视频全部关闭,然后打开下一组视频,在这个切换的过程中,如果是按照常规的做法,比如先关闭再打开新的视频,肯定会出现空白黑屏之类的过度空白区间࿰…...
智能驾驶词典 --- 自动驾驶芯片梳理
0 前言 与智能驾驶相关的芯片主要分为自动驾驶芯片(边缘端)和智能座舱芯片两大类,另外衍生的相关芯片种类还有计算集群芯片(云端), 1 自动驾驶芯片梳理 目前业内具有代表性的智驾芯片产品梳理如下。 1…...
在NVIDIA NX 配置OpenCV多版本冲突和解决的总结
Nvidia Jetson NX 环境 直接刷JetPack5.1的镜像,会得到如下环境 Ubuntu20.04cuda11.4TensorRT8.4cudnn8.4opencv4.5.4 而且这些源一般是从nv-xxxx等源下载的,打开软件Software&Update可以更该是否从这些源安装deb包。同时意味着,我们…...
记录pytorch安装 windows10 64位--(可选)安装paddleseg
安装完paddlepaddle之后,就可以安装paddleseg了。一、安装Git可以参考这个网址:https://blog.csdn.net/u010348546/article/details/124280236windows下安装git和gitbash安装教程二、安装paddleseghttps://github.com/PaddlePaddle/PaddleSeg记得翻墙啊这…...
UWB到底是什么技术?
什么是空间感知能力 所谓的空间感知能力,就是感知方位的能力。更直接一点,就是定位能力。说白了,利用UWB技术,手机和智能设备可以更精准地实现室内定位,不仅可以感知自己的位置,还可以感知周边其它手机或设…...
NCRE计算机等级考试Python真题(八)
第八套试题1、数据库设计中反映用户对数据要求的模式是___________。A.概念模式B.内模式C.设计模式D.外模式正确答案: D2、一个工作人员可使用多台计算机,而一台计算机被多个人使用,则实体工作人员与实体计算机之间的联系是___________。A.多…...
STM32之中断和事件
中断和事件什么是中断当CPU正在执行程序时,由于发生了某种事件,要求CPU暂时中断当前的程序执行,转而去处理这个随机事件,处理完以后,再回到原来被中断的地方,继续原来的程序执行,这样的过程称为…...
MySQL索引类型(type)分析
type索引类型 system > const > eq_ref > ref > range > index > all 优化级别从左往右递减,没有索引的⼀般为’all’。推荐优化目标:至少要达到 range 级别, 要求是 ref 级别, 如果可以是 const 最好ÿ…...
Linux | 2. 用户管理
如有错误,恳请指出。 1. 设置文件权限 权限设置如下: root表示文件所有者,stud1表示文件所属组。其他用户无法访问。更改指令是chown。 更改目录文件所属组:chown .lab lossfound/更改目录文件所有者:chown lab loss…...
【MySQL之SQL语法篇】系统学习MySQL,从应用SQL语法到底层知识讲解,这将是你见过最完成的知识体系
文章目录一、数据管理技术的三个阶段二、SQL语句学习1. DCL数据控制语言1.1 创建用户1.2 修改用户名1.3 修改密码1.4 删除用户1.5 授权1.6 查看权限1.7 回收权限2. DDL数据定义语言2.1 操作数据库2.2 操作数据表2.3 操作数据3. DQL数据查询语言基本语法3.1 单表查询3.1.1选择表…...
CentOS8基础篇7:Linux系统启动配置
一、Linux系统的启动过程 Linux的启动过程大体分为五个阶段: 1.计算机主机加电后,CPU初始化自身,接着在硬件固定位置执行一条指令。这条指令跳转到BIOS,BIOS找到启动设备并获取MBR,该MBR指向LILO或GRUB。 …...
vue中的$forceUpdate()、$set()
$forceUpdate() 迫使vue实例重新(rander)渲染虚拟dom,注意并不是重新加载组件。 结合vue的生命周期,调用 $forceupdate 后只会触发beforeupdate和updated这两个钩子函数,不会触发其他的钩子函数。它仅仅影响实例本身和…...
记住这3点,有效提高江苏专转本上岸率
记住这3点,有效提高上岸率 我们都知道,在江苏统招专转本考试中想岸并不是一件容易的事情。考生能否顺利上岸,往往受多方面因素影响,这其中包括:个人基础、学习方式、信息搜索能力。 如何提高自己的专转本上岸几率&…...
【经验总结】10年的嵌入式开发老手,到底是如何快速学习和使用RT-Thread的?(文末赠书5本)
【经验总结】一位近10年的嵌入式开发老手,到底是如何快速学习和使用RT-Thread的? RT-Thread绝对可以称得上国内优秀且排名靠前的操作系统,在嵌入式IoT领域一直享有盛名。近些年,物联网产业的大热,更是直接将RT-Thread这…...
人大金仓和达梦的空间数据能力对比
一、总得来说: 人大金仓底层更解决于pg数据库, 人大金仓的空间能力基于postgis能力来实现,能力挺强大的. 细节上人大金仓的架构上也对空间的支持框架做的比达梦更加完善。例如数据库的集群能力,并行计算能力,空间数据…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
