You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose如何实现4个Composable组件的单选互斥效果?

预期效果

需求说明

一行有4个Button或Composable组件,需要实现选中一个时自动取消其他选中状态的效果,外观不需要和原生单选按钮一致,但交互逻辑和单选按钮完全相同。


原代码核心问题

  • 为每个按钮单独维护选中状态,需要手动实现互斥逻辑,冗余且容易出错
  • 子组件内部额外维护了本地状态,和父组件传入的参数脱节,导致状态不同步
  • 原有互斥判断逻辑存在分支优先级错误,无法实现预期效果

最优实现方案

核心思路为状态上移+受控组件:整组仅维护一个选中标识状态,所有子按钮的选中态直接和该标识对比判断,点击时直接更新该标识即可自动实现互斥效果。

@Composable
fun ButtonSet(modifier: Modifier = Modifier) {
    // 整组只维护一个选中状态,0~3对应四个按钮,-1表示默认无选中
    var selectedIndex by remember { mutableStateOf(-1) }

    Row(
        modifier = modifier
            .padding(start = 60.dp, end = 60.dp)
            .fillMaxWidth(),
        horizontalArrangement = Arrangement.SpaceEvenly,
    ) {
        // 四个按钮,分别传入对应选中状态和点击回调
        GoalkeeperButton(
            isSelected = selectedIndex == 0,
            onClick = { selectedIndex = 0 }
        )
        GoalkeeperButton(
            isSelected = selectedIndex == 1,
            onClick = { selectedIndex = 1 }
        )
        GoalkeeperButton(
            isSelected = selectedIndex == 2,
            onClick = { selectedIndex = 2 }
        )
        GoalkeeperButton(
            isSelected = selectedIndex == 3,
            onClick = { selectedIndex = 3 }
        )
    }
}

@Composable
fun GoalkeeperButton(
    isSelected: Boolean,
    modifier: Modifier = Modifier,
    onClick: () -> Unit
) {
    Column(
        modifier = modifier
            .wrapContentWidth()
            .height(130.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // 选中时才显示手套图标
        if (isSelected) {
            Image(
                painter = painterResource(id = R.drawable.blue_hands),
                contentDescription = null,
                contentScale = ContentScale.FillBounds,
                modifier = Modifier.size(width = 135.dp, height = 70.dp)
            )
        }
        // 根据选中状态加载不同按钮资源
        Image(
            painter = painterResource(
                id = if (isSelected) R.drawable.bttn_pressed else R.drawable.bttn
            ),
            contentDescription = null,
            contentScale = ContentScale.FillBounds,
            modifier = Modifier
                .clickable(onClick = onClick)
                .size(width = 107.dp, height = 65.dp)
        )
    }
}

优化点说明

  • 代码量减少近一半,没有冗余的状态维护逻辑,单选逻辑天然生效
  • 所有子组件都是受控组件,内部不维护私有状态,不会出现状态不同步问题
  • 合并了重复的激活/未激活按钮组件,减少冗余代码
  • 可扩展性强,后续需要新增按钮时仅需新增对应调用即可,不需要修改互斥逻辑
  • 直接读取selectedIndex即可获取当前选中的选项,不需要额外做状态判断

内容的提问来源于stack exchange,提问作者Ashish Gautam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 14:24:04