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

MaterialButtonToggleGroup点击时addOnButtonCheckedListener触发两次且按钮状态异常

问题原因与解决方案

1. 两次回调的本质原因

点击非当前选中按钮(如btnTest2)的情况

这是设计预期的正常行为:
当singleSelection="true"时,ToggleGroup处于单选模式,切换选中项时会触发两次回调:

  • 第一次:取消原选中按钮的选中状态(isChecked=false,checkedId为原按钮ID)
  • 第二次:选中新按钮的状态(isChecked=true,checkedId为新按钮ID)
    目的是完整告知选中状态的切换过程。

点击当前已选中按钮(如btnTest1)的情况

这是selectionRequired="true"与singleSelection="true"组合导致的逻辑冲突:
当你点击已选中的按钮时,ToggleGroup会先尝试取消它的选中状态(触发isChecked=false的回调),但由于selectionRequired="true"强制要求必须有一个选中项,内部会立即将该按钮重新设为选中状态,从而触发第二次回调(isChecked=true)。你的日志显示回调顺序异常(先true后false),大概率是Material Components库的版本bug,建议升级到最新稳定版。

2. 解决方案

根据业务需求选择对应的处理方式:

方式一:保留单选且允许取消选中

移除布局中的app:selectionRequired="true"属性,这样点击已选中按钮时只会触发一次取消选中的回调,状态也会变为未选中。

方式二:强制保持选中状态(忽略无效取消回调)

如果必须要求始终有一个选中项,只需在监听器中处理isChecked=true的事件即可,忽略isChecked=false的回调(因为此时的取消会被内部回滚,最终状态还是选中):

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    binding.btgTest.addOnButtonCheckedListener { group, checkedId, isChecked ->
        if (isChecked) {
            when (checkedId){
                R.id.btnTest1 -> Timber.d("1 is checked")
                R.id.btnTest2 -> Timber.d("2 is checked")
            }
        }
        // 忽略isChecked=false的回调,避免无效处理
    }
}

方式三:精准处理切换过程(区分有效取消与临时取消)

如果需要记录切换前后的选中状态,可以通过记录上次选中ID来过滤无效的临时取消:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    var lastCheckedId = binding.btgTest.checkedButtonId
    
    binding.btgTest.addOnButtonCheckedListener { group, checkedId, isChecked ->
        if (isChecked) {
            Timber.d("选中按钮: ${if (checkedId == R.id.btnTest1) "1" else "2"}")
            lastCheckedId = checkedId
        } else {
            // 只有当取消的按钮不是上次选中的按钮时,才是有效切换(切换到其他按钮)
            if (checkedId != lastCheckedId) {
                Timber.d("取消按钮: ${if (checkedId == R.id.btnTest1) "1" else "2"}")
            }
            // 否则是点击当前选中按钮导致的临时取消,会被回滚,无需处理
        }
    }
}

方式四:升级Material Components库

在build.gradle中升级到最新稳定版的Material库,修复可能存在的状态回调顺序bug:

dependencies {
    implementation 'com.google.android.material:material:1.11.0' // 替换为最新版本
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 13:34:58