Jetpack Compose实现Surface项点击切换背景色(单选)
实现Column布局下的单选列表背景切换
核心思路
- 在列表组件中维护选中项的状态,用
remember保存选中设备的唯一标识(比如设备地址) - 给可点击容器添加选中状态参数,根据状态切换背景色
- 点击项时更新选中状态,实现同一时间仅选一项的单选逻辑
修改后的完整代码
1. 调整ScanDeviceList,添加选中状态管理
@Composable fun ColumnScope.ScanDeviceList( scanDeviceList: List<ScanResult>, modifier: Modifier = Modifier, pairSelectedDevice: () -> Unit ) { // 用设备地址作为唯一标识,初始为null表示无选中项 val selectedDeviceAddress = remember { mutableStateOf<String?>(null) } Spacer(modifier = Modifier.height(16.dp)) AnimatedVisibility(visible = scanDeviceList.isNotEmpty()) { Column(modifier = modifier) { Text(text = "扫描到的设备") Spacer(modifier = Modifier.height(8.dp)) scanDeviceList.forEachIndexed { index, scanResult -> val isSelected = selectedDeviceAddress.value == scanResult.device.address ClickableItemContainer( rippleColor = AquaLightOpacity10, isSelected = isSelected, content = { ScanDeviceItem(index, scanResult, scanDeviceList.size) } ) { // 点击时切换选中状态:已选中则取消,未选中则设置为当前项 selectedDeviceAddress.value = if (isSelected) null else scanResult.device.address } } AvailableWarningText() PairSelectedDevice(pairSelectedDevice) } } }
2. 修改ClickableItemContainer,支持选中背景色
@OptIn(ExperimentalMaterialApi::class) @Composable fun ClickableItemContainer( rippleColor: Color = TealLight, isSelected: Boolean = false, content: @Composable (MutableInteractionSource) -> Unit, clickAction: () -> Unit ) { val interactionSource = remember { MutableInteractionSource() } // 根据选中状态切换背景色:选中用高亮色,未选中用白色 val backgroundColor = if (isSelected) AquaLightOpacity10 else White CompositionLocalProvider( LocalRippleTheme provides AbcRippleTheme(rippleColor), content = { Surface( onClick = clickAction, interactionSource = interactionSource, color = backgroundColor, modifier = Modifier.fillMaxWidth() ) { content(interactionSource) } } ) }
3. 优化ScanDeviceItem(移除多余参数)
@Composable fun ScanDeviceItem( index: Int, scanResult: ScanResult, totalCount: Int ) { Column { if (index == 0) { Divider(color = Cloudy, thickness = 1.dp) } Text( text = scanResult.device.name, modifier = Modifier.padding(vertical = 10.dp, horizontal = 16.dp) ) // 最后一项不显示分割线 if (index < totalCount - 1) { Divider(color = Cloudy, thickness = 1.dp) } } }
关键说明
- 用设备唯一标识维护选中状态,避免列表重排导致的状态混乱
Surface的color参数直接绑定选中状态,实现背景色实时切换- 支持取消选中:点击已选中项会清空选中状态,符合默认无选中项的需求
- 补全原代码中缺失的
Modifier参数,确保代码可运行
内容的提问来源于stack exchange,提问作者Compose Learner
相关产品推荐
相关产品推荐

