androidandroid-jetpack-composeandroid-jetpackandroid-textinputlayoutandroid-compose-textfield

Jetpack Compose: Custom TextField design


In general, most components in Jetpack Compose seem to be very easy to customize.

However, the same cannot be said for the TextField. For example, say that I wanted to make something like this:

Custom text input

One would think that simply wrapping the BaseTextField would work. However, it appears that there has been a bug in the BaseTextField component, and I have opened an issue. This bug will not permit the user to focus the text field after focusing-away from it once already, until the component is re-rendered.

Citing this, I attempted to customize the OutlinedTextField and TextField components, but am not able to customize them to look like the image above. Were it not for the fact that the cursor color uses the activeColor property, I could make it work.

What would be a proper work-around to create a usable text field that looks like the above?


Solution

  • By this exemple you can learn a lot. With 1.0.0 you can do like this:

    Custom TextField printscreen here

    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
            )
        }