文本字段最大长度 - Android Jetpack Compose

42

是否有现成的解决方案来限制TextField文本框的字符大小?我没有看到像XML中的maxLength参数。

5个回答

78

你可以使用 onValueChange 参数来限制字符数。

var text by remember { mutableStateOf("") }
val maxChar = 5

TextField(
    value = text,
    onValueChange = {
        if (it.length <= maxChar) text = it   
    }
    singleLine = true,
)

然后使用M3,您可以使用supportingText属性来显示counter text
类似这样:

val maxChar = 5

TextField(
    value = text,
    onValueChange = {
        if (it.length <= maxChar) text = it
    },
    modifier = Modifier.fillMaxWidth(),
    supportingText = {
        Text(
            text = "${text.length} / $maxChar",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.End,
        )
    },
)

enter image description here

使用 M2 时,没有内置参数。
在这种情况下,您可以使用类似以下的方式来显示计数器文本

val maxChar = 5

Column(){
    TextField(
        value = text,
        onValueChange = {
            if (it.length <= maxChar) text = it
        },
        singleLine = true,
        modifier = Modifier.fillMaxWidth()
    )
    Text(
        text = "${text.length} / $maxChar",
        textAlign = TextAlign.End,
        style = MaterialTheme.typography.caption,
        modifier = Modifier.fillMaxWidth().padding(end = 16.dp)
    )
}

输入图像描述


5
使用您的代码片段时,如果输入了 maxChar 个字符,则可以正常工作。然后,下一个字符将不会显示任何新字符(正确行为),但是当输入另一个字符(对于 maxChar = 5 的第7个字符)时,它会清除 TextField 并允许重新输入字符。请问这种行为的原因是什么,是否有可能修复? - adek111
8
粘贴长文本是否能够实现?text = it.take(maxChar) 不是更好吗? - John Doe
@adek111 我遇到了同样的问题。你找到了解决方法吗? - Sahil
抱歉,@Sahil,还没有收到Gabriele的解释。 - adek111
@ArpitShukla 这个问题应该在Compose 1.2.0-alpha04版本中得到解决。 - adek111
显示剩余2条评论

9
您可以使用take函数 - 这里的文档
onValueChange = { onYearChanged(it.take(limitNum)) })

例如,如果您将在函数中使用它。
const val limitNum = 4

@Composable
fun YearRow(
  modifier: Modifier = Modifier,
  year: Int, 
  onYearChanged: (String) -> Unit,
) {
  OutlinedTextField(
    modifier = modifier,
    value = if (year == 0) "" else "$year",
    onValueChange = { onYearChanged(it.take(limitNum)) },
  )
}

7
这个问题的第一个答案很好,但是在某些情况下会出现错误,当超过允许的字符数时,文本框的值会被清除。这个故障似乎是由于预测文本引起的,因为如果在Android中禁用预测文本,就不会发生这种情况。我目前找到的一个解决办法是使用 focusManager 来“限制书写”。
首先,我们需要获取焦点管理器来控制屏幕上的焦点。我们可以通过在组合函数中添加以下行来实现:
val focusManager = LocalFocusManager.current

接下来,在我们的TextField中,我们可以使用focusManager来避免用户输入超过maxChar限制。我们可以将焦点移动到下一个元素,在超过maxChar限制时清除焦点或者接收一个lambda函数并执行我们想要的操作。这取决于我们。

var text by remember { mutableStateOf(TextFieldValue("")) }
val maxChar = 10

TextField(
    singleLine = true,
    value = text,
    onValueChange = {
        // This line will take (in case the user try to paste a text from the clipboard) only the allowed amount of characters
        text = it.take(maxChar)
        if (it.length > maxChar){
           focusManager.moveFocus(FocusDirection.Down) // Or receive a lambda function
        }
    }
)

以这种方式,用户永远不能写入超过限制的字符数。显然,这是一种替代解决方案,对我来说解决了我的问题,现在我们必须等待看看他们是否会本地添加它。

6
根据selection,如果新字符串长度超出限制,则删除最近插入的字符。
fun TextFieldValue.ofMaxLength(maxLength: Int): TextFieldValue {
    val overLength = text.length - maxLength
    return if (overLength > 0) {
        val headIndex = selection.end - overLength
        val trailIndex = selection.end
        // Under normal conditions, headIndex >= 0
        if (headIndex >= 0) {
            copy(
                text = text.substring(0, headIndex) + text.substring(trailIndex, text.length),
                selection = TextRange(headIndex)
            )
        } else {
            // exceptional
            copy(text.take(maxLength), selection = TextRange(maxLength))
        }
    } else {
        this
    }
}

用法:

val (phone, setPhone) = remember {
    mutableStateOf(TextFieldValue())
}

PaddingTextField(
    value = phone,
    onValueChange = { newPhone ->
        setPhone(newPhone.ofMaxLength(11))
    }
)

运作得非常顺利! - undefined

-3
另一种更灵活的做法是类似这样的:
Text(
    text = "A string with a lot of charsssssssssssssssssssssssssss"
    modifier = Modifier.fillMaxWidth(.5f),
    maxLines = 1,
    overflow = TextOverflow.Ellipsis
)

这将使用fillMaxWidth位约束宽度,并使用maxLines部分约束高度。如果这两个约束都被触发,文本将溢出,可以指定溢出的行为

在这种情况下,一旦文本占据了视图的一半或超过了一行,它将以类似于A string with a lot of charsssss...的形式结束。


1
问题询问的是输入字段的最大文本长度,而不是最大宽度。 - afollestad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接