Jetpack Compose中BasicTextField用AnimatedVisibility包裹innerTextField触发焦点报错
问题根因
BasicTextField 的 decorationBox 传入的 coreTextField(即你代码中的 innerTextField)必须持续保留在组合树中,不能通过 if 条件判断、AnimatedVisibility 控制它的挂载/卸载。当你失去焦点时输入控件被卸载,再次获得焦点时 BasicTextField 会尝试读取已经卸载的输入控件布局坐标,就会抛出该异常。
解决方案
不要条件卸载输入控件,改为通过透明度、可见性修饰符控制它的显示/隐藏,控件本身始终保留在组合树中即可。
最简复现代码修改示例
把 decorationBox 内的条件渲染逻辑替换为透明度控制:
@Composable fun TextInput( modifier: Modifier = Modifier, value: String, label: String, onValueChanged: (text: String) -> Unit, ) { var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = value)) } val textFieldValue = textFieldValueState.copy(text = value) val interactionSource = remember { MutableInteractionSource() } val isFocused = interactionSource.collectIsFocusedAsState().value BasicTextField( value = textFieldValue, modifier = modifier .defaultMinSize( minWidth = TextFieldDefaults.MinWidth, minHeight = TextFieldDefaults.MinHeight, ), onValueChange = { textFieldValueState = it if (value != it.text) { onValueChanged(it.text) } }, interactionSource = interactionSource, decorationBox = @Composable { coreTextField -> Surface( shape = RoundedCornerShape(), border = BorderStroke( width = 2.dp, color = Colors.Black, ) ) { Column( modifier = Modifier .height(52.dp) .padding(horizontal = 16.dp, vertical = 8.dp), horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Center, ) { Text(text = label) // 用alpha控制显示隐藏,不卸载输入控件 Box(modifier = Modifier.alpha(if (isFocused) 1f else 0f)) { coreTextField() } } } }, ) }
带动画效果的原始代码修改示例
如果需要保留显隐动画,改用属性动画控制透明度,不要使用会卸载子节点的 AnimatedVisibility:
decorationBox = { innerTextField -> Box(Modifier.weight(1f)) { if (addressText.isEmpty()) { Label3(dynamicId = structure?.placeholder) } // 用属性动画实现透明度渐变效果,输入控件始终保留在组合树中 val inputAlpha by animateFloatAsState( targetValue = if (focusAddress) 1f else 0f, label = "inputAlpha" ) Box(Modifier.alpha(inputAlpha)) { innerTextField() } } },
内容的提问来源于stack exchange,提问作者Charles Woodson
相关产品推荐
相关产品推荐

