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.
Related
I ran into an issue today where if I specify a trailing icon for a BasicTextField it forces the height of the field to be increased. Any way to override this setting?
As you can see in the image the 555g field is shorter than the Ingredient1 which became taller due to the addition of the trailingIcon.
I've tried to understand what's happening in compose and after digging I came across this code in the Google native TextField.kt
if (trailing != null) {
Box(
modifier = Modifier
.layoutId(LeadingId)
.then(IconDefaultSizeModifier),
contentAlignment = Alignment.Center
) {
trailing()
}
}
So I am inferring from this that IconDefaultSizeModifier is forcing the minHeight to be 48.dp
and below is the code that I use to create the BasicTextField
BasicTextField(
value = state,
//... more arguments
decorationBox = #Composable {
TextFieldDefaults.OutlinedTextFieldDecorationBox(
value = textVal,
visualTransformation = VisualTransformation.None,
innerTextField = it,
singleLine = singleLine,
enabled = enabled,
interactionSource = interactionSource,
trailingIcon = trailingIcon,
// keep vertical paddings but change the horizontal
contentPadding = TextFieldDefaults.textFieldWithoutLabelPadding(
top = 10.dp,
bottom = 10.dp,
start = 12.dp,
end = 8.dp
),
container = {}
)
}
)
You can apply the same height to both TextFields.
Something like:
BasicTextField(
modifier = Modifier.height(48.dp),
In the same way you can reduce the height.For example
BasicTextField(
modifier = Modifier.height(32.dp),
//... more arguments
decorationBox = #Composable {
TextFieldDefaults.OutlinedTextFieldDecorationBox(
contentPadding = TextFieldDefaults.textFieldWithoutLabelPadding(
top = 0.dp,
bottom = 10.dp,
start = 12.dp,
end = 0.dp
),
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)
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.
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.
Is there a way to produce a resizeable BasicTextField in Jetpack Compose, so that its width would wrap text size when a user types in or deletes characters? They've solved a similar problem for flutter, but I didn't find out how to solve this for Compose.
Flutter - how to make TextField width fit its text ("wrap content")
var text: String by rememberSaveable { mutableStateOf("") }
BasicTextField(
value = text,
onValueChange = {
text = it
},
modifier = Modifier.wrapContentWidth()
)
unfortunately, wrapContentWidth() doesn't work here.
Well, looks like width(IntrinsicSize.Min) solves this problem:
var text: String by rememberSaveable { mutableStateOf("") }
BasicTextField(
value = text,
onValueChange = {
text = it
},
modifier = Modifier.width(IntrinsicSize.Min)
)
We can specify the width range ( min and max width that the textField can span )
for width:-
modifier = Modifier.widthIn(1.dp, Dp.Infinity) // specified the min width as 1.dp
for height:-
modifier = Modifier.heightIn(1.dp, Dp.Infinity)
The composable code:-
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
OutlinedTextField(
value = text,
onValueChange = {
text = it
},
modifier = Modifier.widthIn(1.dp, Dp.Infinity)
)
}
The TextField would grow when we type more till Dp.Infinity. ( used OutlinedTextField for demo but we can use BasicTextField )