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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 12:57:03