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
相关产品推荐
相关产品推荐

