Jetpack Compose: Custom TextField design
Solution 1
By this exemple you can learn a lot. With 1.0.0 you can do like this:
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
)
}
Solution 2
You can use the TextField
:
- removing the label with
label = null
- applying custom color with the
TextFieldDefaults.textFieldColors
parameter to hide the indicator. - adding in the
onValueChange
a function to fix the max number of characters as described here
Finally use a Column
to add 2 Text
composables to complete the external label and counter text.
Something like:
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()
)
Solution 3
Well, until the issue I mentioned is resolved, the choices are:
- Roll back to Compose version
1.0.0-alpha04
(issue was introduced inalpha05
) - Add a border to a
TextField
orOutlinedTextField
as so:TextField( value = myValue, onValueChange = myOnChange, modifier = Modifier.clip(myShape).border(5.dp, myColor) )
foxtrotuniform6969
Updated on June 06, 2022Comments
-
foxtrotuniform6969 about 2 years
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:One would think that simply wrapping the
BaseTextField
would work. However, it appears that there has been a bug in theBaseTextField
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
andTextField
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 theactiveColor
property, I could make it work.What would be a proper work-around to create a usable text field that looks like the above?