Jetpack Compose:自定义文本框设计

42

总的来说,Jetpack Compose中的大多数组件似乎都很容易定制。

然而,对于TextField,情况并非如此。例如,假设我想制作类似于下面这样的东西:

Custom text input

人们可能认为只需包装BaseTextField即可。但是,BaseTextField组件中存在一个错误,我已经报告了该问题。这个错误将不允许用户在一次聚焦前后集中文本字段,直到重新渲染该组件。

鉴于此,我尝试自定义OutlinedTextFieldTextField组件,但无法将它们定制成像上面的图像那样的外观。如果不是由于光标颜色使用activeColor属性,我就可以实现它。

有什么适当的解决方法来创建一个看起来像上面的可用文本字段呢?


你如何在TextField下方显示字符计数器? - Thracian
@Thracian 嗯,您需要将所有内容都包装在一个列中,以便计数器出现在文本字段下方,然后使用文本字段的状态来获取“.length”。 - foxtrotuniform6969
非常感谢。我以为这是TextField的本地组件。我猜还没有字符计数器、辅助文本和错误消息。 - Thracian
你如何从TextField中去掉下划线?我也无法去掉它。我正在尝试创建一个没有下划线的圆角TextField,用于带有前导图标的TopBar搜索。BasicTextField没有图标属性,所以我正在尝试使用TextField来实现,但如果不起作用,我将手动使用BasicTextField和Image来完成。 - Thracian
你需要添加一个足够粗的边框来覆盖现有的线。 - foxtrotuniform6969
4个回答

45

您可以使用 TextField

  • 通过 label = null 删除标签
  • 使用 TextFieldDefaults.textFieldColors 参数应用自定义颜色以隐藏指示器
  • onValueChange 中添加一个函数来限制字符的最大数量,如此处所述:here

最后,使用 Column 添加 2个 Text 组合成件,以完成外部标签和计数器文本。

类似于:

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

Column(){
    //External label
    Text(
        text = "Label",
        modifier = Modifier.fillMaxWidth(),
        textAlign = TextAlign.Start,
        color = Blue
    )

    TextField(
        value = text,
        onValueChange = {
            if (it.length <= maxChar) text = it
        },
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 4.dp),
        shape = RoundedCornerShape(8.dp),
        trailingIcon = {
            Icon(Icons.Filled.Add, "", tint = Blue)
        },
        colors = TextFieldDefaults.textFieldColors(
            backgroundColor = ....,
            focusedIndicatorColor =  Color.Transparent, //hide the indicator
            unfocusedIndicatorColor = .....)
    )
    //counter message
    Text(
        text = "${text.length} / $maxChar",
        textAlign = TextAlign.End,
        color = Blue,
        style = MaterialTheme.typography.caption, //use the caption text style
        modifier = Modifier.fillMaxWidth()
    )

在此输入图片描述


34

通过这个例子,你可以学到很多东西。有了1.0.0,你可以这样做:

自定义文本字段截图

Column {
        var textState by remember { mutableStateOf("") }
        val maxLength = 110
        val lightBlue = Color(0xffd8e6ff)
        val blue = Color(0xff76a9ff)
        Text(
            text = "Caption",
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 4.dp),
            textAlign = TextAlign.Start,
            color = blue
        )
        TextField(
            modifier = Modifier.fillMaxWidth(),
            value = textState,
            colors = TextFieldDefaults.textFieldColors(
                backgroundColor = lightBlue,
                cursorColor = Color.Black,
                disabledLabelColor = lightBlue,
                focusedIndicatorColor = Color.Transparent,
                unfocusedIndicatorColor = Color.Transparent
            ),
            onValueChange = {
                if (it.length <= maxLength) textState = it
            },
            shape = RoundedCornerShape(8.dp),
            singleLine = true,
            trailingIcon = {
                if (textState.isNotEmpty()) {
                    IconButton(onClick = { textState = "" }) {
                        Icon(
                            imageVector = Icons.Outlined.Close,
                            contentDescription = null
                        )
                    }
                }
            }
        )
        Text(
            text = "${textState.length} / $maxLength",
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 4.dp),
            textAlign = TextAlign.End,
            color = blue
        )
    }

6

好的,直到我提到的问题得到解决之前,可供选择的有:

  1. Roll back to Compose version 1.0.0-alpha04 (issue was introduced in alpha05)
  2. Add a border to a TextField or OutlinedTextField as so:
    TextField(
        value = myValue,
        onValueChange = myOnChange,
        modifier = Modifier.clip(myShape).border(5.dp, myColor)
    )
    

2
在更新的版本中,您需要将形状传递给TextField本身,因为它会用传入的形状覆盖剪辑参数。 - EpicPandaForce

2
除了Gabriele Mariotti的回答之外,如果您想要自定义光标颜色,可以使用以下方法实现:
Column(){
    //External label
    Text(
        ...
        ...
    )

    TextField(
        ...
        ...

        colors = TextFieldDefaults.textFieldColors(
            backgroundColor = ...,
            focusedIndicatorColor =  ..., 
            unfocusedIndicatorColor = ...,
            cursorColor = Color.Black)
    )
    //counter message
    Text(
        ...
        ...
    )

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