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

如何让rememberSaveable在movableContentOf中正常生效?

问题根因

movableContentOf 会在结构变化(比如父容器从Row切换为Column、配置变更触发重组)时,将内部的Composable节点从旧位置直接移动到新位置,避免节点重新创建。但它默认不会为内部内容绑定稳定的状态保存键:

  • 普通remember声明的状态直接绑定在movableContent持有的节点实例上,节点移动过程中没有被销毁,所以状态能正常保留,就是示例里第一个Checkbox状态不丢的原因。
  • rememberSaveable的状态是通过视图树中的位置键做索引,存在SaveableStateRegistry里的。当movableContent在不同父容器间移动时,系统会判定旧位置的节点已被移除,直接清除对应位置键绑定的保存状态,旋转后自然读不到之前存的值。
修复方案

二选一即可,都能解决状态丢失问题:

  • 方案1:为movableContent绑定固定唯一键
    在两个调用movableContent的位置,用相同的固定key包裹内容,保证不管外层容器怎么切换,状态保存用的索引键始终不变,SaveableStateRegistry就能正确关联到之前存储的状态:
    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
    
        val content = remember {
            movableContentOf {
                var a by remember { mutableStateOf(false) }
                Checkbox(a, { a = it })
                var b by rememberSaveable { mutableStateOf(false) }
                Checkbox(b, { b = it })
            }
        }
    
        var switch by rememberSaveable { mutableStateOf(false) }
        Checkbox(switch, { switch = it })
        // 两个分支使用完全相同的key,保证状态索引稳定
        if (switch) Row { key("fixed_nav_content_key") { content() } } 
        else Column { key("fixed_nav_content_key") { content() } }
    
    }
    
  • 方案2:将需要跨配置保存的状态提升到movableContent外层
    把所有用rememberSaveable声明的状态提到movableContent的外部持有,通过参数传给内部组件,状态的保存逻辑完全不受节点移动、容器切换的影响,稳定性更高:
    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        // 状态提升到外层,依托外层稳定的位置完成保存
        var b by rememberSaveable { mutableStateOf(false) }
        val content = remember {
            movableContentOf {
                var a by remember { mutableStateOf(false) }
                Checkbox(a, { a = it })
                Checkbox(b, { b = it })
            }
        }
    
        var switch by rememberSaveable { mutableStateOf(false) }
        Checkbox(switch, { switch = it })
        if (switch) Row { content() } else Column { content() }
    }
    

如果是开发适配不同屏幕尺寸的导航类组件,优先选方案2,状态统一在上层管理,后续新增其他尺寸的布局适配时,也不会因为movableContent的位置变化触发状态丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:09:11