I'm trying to make a textfield thats quite small (32.dp). When doing this, the label gets pushed to the bottom and I can't find a way to keep it centered? I've tried using TextAlign.center but no luck
TextField(
modifier = Modifier
.height(32.dp)
.padding(horizontal = 8.dp)
.border(1.dp, colorResource(id = R.color.mono4), RoundedCornerShape(32.dp))
.constrainAs(commentBox) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(profilePhoto.end)
end.linkTo(postText.start)
width = Dimension.fillToConstraints
height = Dimension.fillToConstraints
},
label = {
Text(
textAlign = TextAlign.Center,
text = "Comment on workout...",
style = TextStyle(
fontSize = 14.sp,
color = colorResource(id = R.color.mono4),
fontFamily = FontFamily(Font(R.font.josefin_san_regular))
)
)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
),
value = commentText,
onValueChange = { commentText = it }
)
This is internal behaviour, you will need to alter the source coe to fix it, or implement your own composable, something like:-
#OptIn(ExperimentalAnimationApi::class)
#Composable
fun TinyTextCapture(){
var value by remember { mutableStateOf("") }
Box(contentAlignment = Alignment.Center){
TextField(
modifier = Modifier.height(32.dp),
value = value, onValueChange = { value = it }
)
AnimatedVisibility(visible = value.isEmpty()) {
Text("Label")
}
}
}
The default label parameter has a default padding from top start, that is why it was seen as being pushed downwards. If I were you, I would not go about editing the source of something as basic as a TextField since it has so many internal dependencies that it is all a mess.
You could also do without the AnimatedVisibility, and also apply a ConstraintLayout to get it at the start of the TextField in contrast to its absolute centered position right now.
Related
Quick question here:
Is this a bug inside jetpack compose TextField or am I missing something:
#Composable
fun TextFieldWithPlaceholder() {
val text = rememberSaveable {
mutableStateOf("")
}
Box(modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)) {
TextField(
modifier = Modifier
.background(Color.Blue)
.size(width = 300.dp, height = 50.dp),
value = text.value,
onValueChange = { value ->
text.value = value
},
singleLine = true,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = Color.Transparent,
unfocusedLabelColor = Color.Transparent,
placeholderColor = Color.Red,
cursorColor = Color.White
),
placeholder = {
Text(
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
text = "Placeholder"
)
},
textStyle = MaterialTheme.typography.body2.copy(textAlign = TextAlign.Center)
)
}
}
If you build the project with this composable, and tap inside the input field, you'll notice that the cursor is behind the placeholder text (talking about the Z axis). Parts of the cursor are not visible due to "Placeholder" text being on top of it.
Is there a way to force it to be on top of placeholder?
Thanks in advance
Hey guys I am learning textfield in jetpack compose. I want to use multiple time so I make a function and use it. when I am passing start padding it decreases the width of other one. Can someone help me on this, where i am wrong here.
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
repeat(2){
val value = if (it == 1){
21.dp
}else {
15.dp
}
var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue())
}
TextField(
value = textFieldValue,
singleLine = true,
onValueChange = {
if (it.text.length <= 4) {
textFieldValue = it
}
},
modifier = Modifier
.height(55.dp)
.width(88.dp)
.padding(start = value),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = OffWhite,
focusedIndicatorColor = TealLight,
cursorColor = TealLight
),
textStyle = RegularSlate20
)
}
}
It look like this
why my 2nd textfield is not 88.dp?
The order of the modifiers is important.
You have to use:
TextField(
//....
modifier = Modifier
.height(55.dp)
.padding(start = value) //apply the padding before the width modifier
.width(88.dp)
)
I have two layers in my Compose layout: One for the actual content and the one above is a Box-wrapped OutlinedTextField for search queries.
Here's the sample code:
// Placeholder for layout content
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(id = R.string.lorem_ipsum),
color = Color.Gray
)
}
// Overlaying Box with OutlinedTextField
Box(modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp, top = 64.dp)
) {
OutlinedTextField(
value = viewModel.query.value,
onValueChange = { viewModel.updateQuery(it) },
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.navigationBarsWithImePadding(),
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Characters,
autoCorrect = false,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.None
),
shape = CircleShape,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.White
),
placeholder = { Text(stringResource(id = R.string.search_input_placeholder)) },
maxLines = 1,
singleLine = true
)
}
Even though I'm setting
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.White
)
in the OutlinedTextField, the background stays transparent as you can see in the following screenshot:
Adding a background color on the OutlinedTextField's modifier is giving the whole row a rectangled background, which is also not the desired result.
The OutlinedTextField with it's CircleShape should only have a background inside of the shape. How can I achieve that?
I'm using Jetpack Compose version 1.0.4.
Reason
Unfortunately, in version 1.0.4, OutlinedTextField ignores the backgroundColor even if you specify it, so you can remove the colors parameter.
Support for it will be added in 1.1.0:
https://android-review.googlesource.com/c/platform/frameworks/support/+/1741240
It's already present in 1.1.0-alpha06 so you can play with it if you want. Your original code should produce desired outcome on that version.
Solution
To achieve what you want (before 1.1.0 is released) you can simply add a background modifier with the same shape:
.background(Color.White, CircleShape)
Since the order of modifiers is important, you should add it after you apply all the paddings (navigationBarsWithImePadding in your case). Like that:
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.navigationBarsWithImePadding()
.background(Color.White, CircleShape),
Note: Also be aware that you cannot use the label parameter with this approach, because the TextField with label will be higher than just the outline shape and these two shaped wouldn't match in size anymore.
Result
Entire code:
// Placeholder for layout content
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(id = R.string.lorem_ipsum),
color = Color.Gray
)
}
// Overlaying Box with OutlinedTextField
Box(modifier = Modifier
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp, top = 64.dp)
) {
OutlinedTextField(
value = viewModel.query.value,
onValueChange = { viewModel.updateQuery(it) },
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.navigationBarsWithImePadding()
.background(Color.White, CircleShape),
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Characters,
autoCorrect = false,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.None
),
shape = CircleShape,
placeholder = { Text(stringResource(id = R.string.search_input_placeholder)) },
maxLines = 1,
singleLine = true
)
}
How the final result looks like:
I have created a Text within a TextField to work as hint. I want to reduce the distance between the underbar and the hint text. How do I do that? I have tried using the following code:
TextField(
value = query.value,
onValueChange = { newValue -> query.value = newValue },
label = {
Text(
"Name as on Pan Card",
color = colorResource(id = R.color.fade_green),
modifier = Modifier.align(BottomCenter) //THIS LINE PRODUCES ERROR
)
},
textStyle = TextStyle(
textAlign = TextAlign.Start,
color = colorResource(id = R.color.fade_green),
fontFamily = FontFamily(Font(R.font.poppins_regular)),
fontSize = with(LocalDensity.current){
dimensionResource(id = R.dimen._11ssp).toSp()},
),
modifier = Modifier
.align(
CenterHorizontally
)
.weight(0.3f),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
unfocusedIndicatorColor = colorResource(id = R.color.bright_green),
focusedIndicatorColor = colorResource(id = R.color.bright_green)
)
)
I am getting the error 'fun Modifier.align(alignment : Alignment) : Modifier can't be called in this context by implicit receiver. Use the explicit one if necessary'
How do I solve this?
Instead of
modifier = Modifier.align(BottomCenter)
use
modifier = Modifier.align(Alignment.BottomCenter)
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 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?
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()
)
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
)
}
Well, until the issue I mentioned is resolved, the choices are:
Roll back to Compose version 1.0.0-alpha04 (issue was introduced in alpha05)
Add a border to a TextField or OutlinedTextField as so:
TextField(
value = myValue,
onValueChange = myOnChange,
modifier = Modifier.clip(myShape).border(5.dp, myColor)
)
In addition to Gabriele Mariotti's Answer
If you like to have custom color for your cursor, you can achieve it using:
Column(){
//External label
Text(
...
...
)
TextField(
...
...
colors = TextFieldDefaults.textFieldColors(
backgroundColor = ...,
focusedIndicatorColor = ...,
unfocusedIndicatorColor = ...,
cursorColor = Color.Black)
)
//counter message
Text(
...
...
)