Always display placeholder and RTL input in TextField with Jetpack Compose - android

I want the placeholder not to disappear if I start typing in a field and it should be on the left side of the screen.
But the text input and cursor must be on the right.
An example is in the screenshot. Thanks!

Not the best solution, but it works.
Customizing the placeholder as per the requirement is not possible at this point in time. You have to create a completely customized TextField if that is an absolute requirement.
Note.
This is not a placeholder.
The positioning of the text is absolute, it should be adjusted according to the TextField size.
#Composable
fun FixedPlaceholder() {
var name by remember { mutableStateOf("") }
Box {
OutlinedTextField(
shape = MaterialTheme.shapes.medium,
value = name,
onValueChange = {
name = it
},
singleLine = true,
textStyle = LocalTextStyle.current.copy(
textAlign = TextAlign.End,
),
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = 16.dp,
vertical = 8.dp,
),
)
Text(
text = "to",
modifier = Modifier
.fillMaxWidth()
.padding(
start = 32.dp,
end = 32.dp,
top = 24.dp,
bottom = 8.dp
),
)
}
}

You don't need the placeholder, just set the leadingIcon property to:
leadingIcon={Text(text="To")}
In Compose, leadingIcon is a composable, and you can set it to anything you like.

Related

Jetpack Compose TextField cuts text on scroll

I have a TextField with a fixed height. When the user enters a longer text it will scroll. It will cut off any text within the padding when scrolling:
Basically something like this:
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { value -> text = value },
modifier = modifier
.fillMaxWidth()
.height(100.dp),
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
backgroundColor = Color.Transparent
)
)
It is possible to adjust/remove the padding for a TextField, by using BasicTextField directly, e.g. see this stack overflow question.
However I want to keep the padding, but without the clipping of the text when the user scrolls. A simple Text Composable has this behavior.
You can use BasicTextField and modify its decorationBox parameter.
Simply put innerTextField() inside a scrollable Column and add Spacers at the top and the bottom of it.
var text by remember {
mutableStateOf("Hello Stackoverflow")
}
val paddingSize = remember { 16.dp }
BasicTextField(
modifier = Modifier
.height(100.dp),
value = text,
onValueChange = { text = it },
decorationBox = { innerTextField ->
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(state = rememberScrollState())
) {
Spacer(modifier = Modifier.height(paddingSize))
innerTextField()
Spacer(modifier = Modifier.height(paddingSize))
}
}
)
Just use the maxLines parameter of the TextField to avoid clipping. Set it to 1 or 2, per your case, then adjust the height/font-size so the max lines you specify are accomodated correctly. It will likely start to snap to the visible portion, cutting the extra stuff entirely.

How to remove padding in text line on Jetpack Compose

I faced with a problem related to Text element in Jetpack Compose. I wanted to place two separated Text elements under each other but I can't remove their inner paddings to make them look like not so separated.
As you can see on pic below Text with "02" has these paddings. Is there any way to crop them?
I tried to use .offset() and .height() modifiers to change the Text box size, but it looks like a really awful solution.
Code example to reproduce:
Box(
modifier = Modifier
.height(65.dp)
.width(65.dp)
.background(Color.White)
) {
Column(
modifier = Modifier
.align(Alignment.Center)
) {
Text(
text = "00",
maxLines = 1,
overflow = TextOverflow.Clip,
style = MaterialTheme.typography.h5.copy(
fontWeight = FontWeight.SemiBold
),
color = Color.Black,
modifier = Modifier
.align(Alignment.CenterHorizontally)
)
Text(
text = "Text",
style = MaterialTheme.typography.body2,
color = Color.Gray,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
}
Thanks in advance!

How to remove RadioButton's padding in Jetpack Compose?

I have a problem with RadioButton component in my Jetpack Compose application. I have some RadioButtons with text and this have a lot of padding by default. Can I remove this padding or to set a custom padding to avoid a lot of space between each?
Currently I have this:
My code is:
Column {
MyEnum.values().filter { rb -> rb.visible }.forEach { rb ->
Row(
Modifier
.fillMaxWidth()
.padding(horizontal = 0.dp, vertical = 0.dp)
.clickable(
interactionSource = interactionSource,
indication = null
) {
TODO()
},
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = (rb.position == selectedOption),
onClick = {
TODO()
},
colors = RadioButtonDefaults.colors(
selectedColor = DialogOutlinedTextFocus,
unselectedColor = DialogOutlinedTextUnfocus
)
)
Text(
text = stringResource(id = rb.idText),
color = Color.Black,
fontSize = 14.sp,
modifier = Modifier
.padding(horizontal = 3.dp, vertical = 2.dp)
)
}
}
}
I tried with contentPadding, but this property does not exist in RadioButton component.
The source code for RadioButton.kt sets the padding modifier at line 108. With modifiers, order matters. Even if you provide your own padding modifier it will be overridden by line 108.
The sizing values are hardcoded at the bottom of the file.
If you really want to "reduce the padding", apply a size modifier. I use 20.dp because it's equal to radioButtonSize in RadioButton.kt so the button doesn't get clipped. This should work for your purposes since the entire row is clickable.
RadioButton(
modifier = Modifier.size(20.dp),
selected = selected,
onClick = { TODO() },
)
Although, you're probably better off in the long term making custom components you can control. Luckily, the source code is ready available. Just copy, paste and adjust to your needs.
You could specify the Row height in the Row.Modifier
like this:
Row(
Modifier
.fillMaxWidth()
//HERE YOU GO
.height(30.dp)
.padding(horizontal = 0.dp, vertical = 0.dp)

Jetpack Compose Textfield Label not staying in center

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.

Jetpack Compose: No background in OutlinedTextField

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:

Categories

Resources