Jetpack Compose中自定义类作为TextField值无法在重组后保留输入内容
问题原因
这个问题的核心是Jetpack Compose的MutableState重组触发逻辑:
- 你用
var xx by mutableStateOf(...)声明变量时,by关键字仅代理对xx变量本身的读写操作:只有你主动给xx赋值(也就是调用State的setValue方法)时,Compose才会比对新旧值,判断是否需要触发界面重组。 - 第一个
TextField能正常工作,是因为String是不可变类型,onValueChange = { text = it }直接给State代理的text变量赋了新的String实例,触发了State的更新逻辑,所以界面会刷新。 - 第二个
TextField出问题,是因为你修改的是strHolder指向的StrHolder对象内部的s属性,自始至终都没有给strHolder变量本身赋新值,State完全感知不到内部属性的变更,不会触发重组,界面自然不会更新。
修复方案
有两种常见的修复思路:
方案1:修改时替换整个State持有的对象
每次属性变更时直接给strHolder赋新的StrHolder实例,触发State的更新:
TextField( value = strHolder.s, onValueChange = { strHolder = StrHolder(it) }, )
如果StrHolder有多个属性需要修改,可以声明为数据类,用copy方法生成新实例:
// 先将StrHolder声明为data class data class StrHolder(var s: String, var otherField: Int = 0) // 修改属性时调用copy生成新实例赋值 onValueChange = { strHolder = strHolder.copy(s = it) }
方案2:让StrHolder的属性本身可被观察
把需要响应变化的属性声明为MutableState,这样就算外部不替换StrHolder实例,属性变更也能直接触发重组:
class StrHolder(s: String) { var s by mutableStateOf(s) } // 使用时不需要改调用逻辑,原有onValueChange写法就能生效 TextField( value = strHolder.s, onValueChange = { strHolder.s = it }, )
内容的提问来源于stack exchange,提问作者Herman
相关产品推荐
相关产品推荐

