This commit is contained in:
coco
2026-07-15 16:57:36 +08:00
parent 723ce1af5c
commit 95aa018b8b
314 changed files with 8910 additions and 0 deletions
@@ -0,0 +1,84 @@
# How to show hint with underline in a TextField
!!! info
This is the API of version dev08. Newer versions may have a different one
We have all used EditText in classic Android development. It has lots of features like hint showing or default underline background. In Jetpack compose it's name is TextField
and we set up it like that.
## Create TextField
```kotlin
val state = state { "" }
TextField(
value = state.value,
modifier = modifier,
onValueChange = { state.value = it },
textStyle = yourTextStyle
)
```
With textStyle parameter you can change your TextField's font, font size, color and many other things, but there are something that its missing, you cant quite set its PlaceHolder
text(Hint). So how can we do that? If you think about that hint's only purpose is to be shown when TextField is empty and be hidden when we are starting to type something in TextField.
So we need two views one Text for hint showing and one TextField. They must have same location on the screen so it will look like same component. So without further ado let's start
implementing it.
## Create HintTextField
```kotlin
@Composable
fun HintEditText(
hintText: String = "",
modifier: Modifier = Modifier.None,
textStyle: TextStyle = currentTextStyle()
) {
val state = state { "" }
val inputField = @Composable {
TextField(
value = state.value,
modifier = modifier,
onValueChange = { state.value = it },
textStyle = textStyle.merge(TextStyle(textDecoration = TextDecoration.None))
)
}
Layout(
children = @Composable {
inputField()
Text(
text = hintText,
modifier = modifier,
style = textStyle.merge(TextStyle(color = Color.Gray))
)
Divider(color = Color.Black, height = 2.dp)
},
measureBlock = { measurables: List<Measurable>, constraints: Constraints, _ ->
val inputFieldPlace = measurables[0].measure(constraints)
val hintEditPlace = measurables[1].measure(constraints)
val dividerEditPlace = measurables[2].measure(
Constraints(constraints.minWidth, constraints.maxWidth, 2.ipx, 2.ipx)
)
layout(
inputFieldPlace.width,
inputFieldPlace.height + dividerEditPlace.height
) {
inputFieldPlace.place(0.ipx, 0.ipx)
if (state.value.isEmpty())
hintEditPlace.place(0.ipx, 0.ipx)
dividerEditPlace.place(0.ipx, inputFieldPlace.height)
}
})
}
```
Seems like lots of code for simple functional, doesnt it? Lets describe whats happening from the function declaration. It has three function parameters and they are pretty
self-explanatory. As second part we are creating TextField lambda and passing it in Layout Composable function, with our HintText and Divider, which as you might have guessed
will create underline background. Now it's time to decide where we are going to put our HintTextField.
First of all we need to measure our views and **measureBlock** will help us do that.
Measurables list will contain three items(Our TextField, HintText and Divider) as Measurable type, we need to call measure on all of list items and pass constraints in it. Constraints
is a class which only has four properties(minWidth, maxWidth, minHeight, maxHeight). We can pass constraints which is given to us by measuring @Composable children lambda, which works
with our TextField and HintText because we want them to have same size as it's parent, but when it comes to underline background we need it to stay as thin as possible.
Now we are measuring our HintTextField one more time and placing it's children on some (x, y).
One last thing to realize is that if our state value is not empty we dont place
our HintText at all!