如何在LazyColumn中实现仅单个AnimatedVisibility为true的卡片展开效果
解决方案
问题核心原因
现在每张OSCard都在内部独立维护了自己的expanded状态,卡片之间没有状态关联,所以会出现多张同时展开的情况。我们只需要把展开状态向上提升到列表父组件统一管理即可实现需求。
具体修改步骤
1. 修改OSCard组件,将状态和点击事件外置
去掉组件内部维护的展开状态,改为从参数传入,同时接收外部的点击回调,修改后代码如下:
@ExperimentalAnimationApi @Composable fun OSCard( os: OS, isExpanded: Boolean, onCardClick: () -> Unit ) { Column( modifier = Modifier .clickable { onCardClick() } .fillMaxWidth() ) { Text( modifier = Modifier.padding(20.dp), text = os.name, style = MaterialTheme.typography.h6 ) AnimatedVisibility(visible = isExpanded) { Text(text = os.description, modifier = Modifier.padding(20.dp)) } Divider(Modifier.height(2.dp)) } }
2. 父组件统一管理展开状态
在列表所在的父组件新增状态保存当前展开的操作系统标识,点击时更新状态即可实现自动收起其他卡片的效果:
val OSs = listOf<OS>( OS( "Android", "Android is a mobile/desktop operating system..." ), OS( "Microsoft Windows", "Microsoft Windows, commonly referred to as Windows..." ), OS( "Linux", "Linux is a family of open-source Unix-like operating systems..." ) ) Surface(color = MaterialTheme.colors.background) { // 保存当前展开的系统名称,null表示没有展开的卡片 var selectedOsName by remember { mutableStateOf<String?>(null) } LazyColumn(modifier = Modifier.fillMaxSize()) { items(items = OSs) { os -> OSCard( os = os, // 判断当前卡片是否是选中展开的 isExpanded = os.name == selectedOsName, onCardClick = { selectedOsName = if (os.name == selectedOsName) { // 点击已经展开的卡片,直接收起 null } else { // 点击其他卡片,切换为当前卡片展开 os.name } } ) } } }
提示:如果存在同名系统的可能,推荐给
OS数据类新增唯一id字段,使用id代替name作为判断展开的标识,逻辑会更严谨。
内容的提问来源于stack exchange,提问作者Kinyo356
相关产品推荐
相关产品推荐

