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

Jetpack Compose OTP TextField最后单元格宽度缩小问题求助

解决Jetpack Compose OTP输入框最后一个单元格宽度被压缩的问题

问题原因

当前实现中,每个OTP单元格固定为50dp宽度,加上单元格间8dp的Spacer,当设备屏幕宽度较小时,Row的总布局宽度会超出可用空间,导致最后一个单元格被强制挤压缩小。

解决方案

方案1:自适应平分可用宽度(推荐)

让每个OTP单元格平分Row的可用宽度,同时设置最小宽度避免过窄,用水平padding替代固定Spacer,确保布局在所有屏幕上都能正常展示。

修改后的代码:

Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
    BasicTextField(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight(),
        value = TextFieldValue(otpText, selection = TextRange(otpText.length)),
        onValueChange = {
            onOtpTextChange(it.text)
        },
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),
        decorationBox = { innerTextField ->
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                repeat(otpCount) { index ->
                    CharView(
                        index = index,
                        text = otpText,
                        isError = isError,
                    )
                }
            }
        },
    )
}

@Composable
private fun CharView(
    index: Int,
    text: String,
    isError: Boolean
) {
    val isFocused = text.length == index
    val char = when {
        index >= text.length -> ""
        else -> text[index].toString()
    }
    Text(
        modifier = Modifier
            .weight(1f)
            .minWidth(40.dp)
            .height(60.dp)
            .clip(MaterialTheme.shapes.large)
            .border(
                1.dp, when {
                    isFocused -> Orange
                    else -> Gray
                }, RoundedCornerShape(4.dp)
            )
            .padding(horizontal = 8.dp, top = 10.dp),
        text = char,
        style = TextStyle(
            fontWeight = FontWeight.Bold,
            fontSize = 28.sp,
            letterSpacing = 0.sp,
            color = Color.Black
        ),
        color = Color.Black,
        textAlign = TextAlign.Center
    )
}

方案2:固定单元格大小+横向滚动

如果需要保持单元格固定宽度,可给Row添加横向滚动,让用户在空间不足时滚动查看所有单元格。

修改后的代码:

Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
    BasicTextField(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight(),
        value = TextFieldValue(otpText, selection = TextRange(otpText.length)),
        onValueChange = {
            onOtpTextChange(it.text)
        },
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),
        decorationBox = { innerTextField ->
            val scrollState = rememberScrollState()
            Row(
                modifier = Modifier.horizontalScroll(scrollState),
                horizontalArrangement = Arrangement.Center
            ) {
                repeat(otpCount) { index ->
                    CharView(
                        index = index,
                        text = otpText,
                        isError = isError,
                    )
                    if (index != otpCount - 1) {
                        Spacer(modifier = Modifier.width(8.dp))
                    }
                }
            }
        },
    )
}

@Composable
private fun CharView(
    index: Int,
    text: String,
    isError: Boolean
) {
    val isFocused = text.length == index
    val char = when {
        index >= text.length -> ""
        else -> text[index].toString()
    }
    Text(
        modifier = Modifier
            .width(50.dp)
            .height(60.dp)
            .clip(MaterialTheme.shapes.large)
            .border(
                1.dp, when {
                    isFocused -> Orange
                    else -> Gray
                }, RoundedCornerShape(4.dp)
            )
            .padding(top = 10.dp),
        text = char,
        style = TextStyle(
            fontWeight = FontWeight.Bold,
            fontSize = 28.sp,
            letterSpacing = 0.sp,
            color = Color.Black
        ),
        color = Color.Black,
        textAlign = TextAlign.Center
    )
}

方案选择

  • 方案1适用于大多数场景,能自适应不同屏幕宽度,保证布局一致性;
  • 方案2适合需要严格固定单元格尺寸的需求,通过滚动解决空间不足问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 01:27:53