Resizeable BasicTextField in Jetpack Compose - android

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 )

Related

How to create multiline text area in jetpack compose

I want to create the following textfield. But there are no samples on the internet for the same, neither in material documentation
#Composable
fun Textarea() {
val text = rememberSaveable { mutableStateOf("") }
TextField(
value = text.value,
onValueChange = { text.value = it }, modifier = Modifier
.fillMaxWidth()
.height(100.dp)
.padding(10.dp)
.border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(8.dp))
)
}
You can change the size and customize it as you want as per your requirement.

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.

Change the trailingIcon size of a TextField

TextField trainlingIcon has a default size inside the class it wraps the composable inside a box with a default size
TextField.kt
Box(
modifier = Modifier.layoutId(TrailingId).then(IconDefaultSizeModifier),
contentAlignment = Alignment.Center
) {
Decoration(
contentColor = trailingColor,
content = trailing
)
}
}
where the default value is defined in TextFieldImple.Kt
internal val IconDefaultSizeModifier = Modifier.defaultMinSize(48.dp, 48.dp)
this causes unwanted space for the textField
is there a way to override this?

How change OutlineTextField border width in Android Jetpack Compose?

My code:
OutlinedTextField(
value = state.value,
onValueChange = { state.value = it },
modifier = Modifier.fillMaxWidth().padding(start = 30.dp, end = 30.dp),
label = { Text(text = "Something", fontSize = 14.sp) },
shape = RoundedCornerShape(12.dp),
)
I want to increase the border width so that the colors focusedBorderColor, disabledBorderColor are supported.
Outline border is defined as a constant value in OutlinedTextField.
private val IndicatorUnfocusedWidth = 1.dp
private val IndicatorFocusedWidth = 2.dp
There is no direct way to override these values.
So, you have to create complete custom TextField Composables if you need to achieve dynamic border width.
You can copy-paste the complete code in OutlinedTextField.kt and TextFieldImpl.kt and modify them as required to create the custom Composables.
You can change OutlinedTextField border like this
var hasFocus by remember { mutableStateOf(false) }
OutlinedTextField(
modifier = modifier
.border(
width = 1.dp,
color = if (hasFocus) Color.Red else Color.Unspecified
)
.onFocusChanged { focusState -> hasFocus = focusState.hasFocus },
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.Unspecified,
unfocusedBorderColor = Color.Unspecified
)
)
Another solution is to use BaseTextField instead of OutlinedTextField

Dense TextField in Jetpack Compose

In the old View system, we can make TextInputLayout dense using style Widget.MaterialComponents.TextInputLayout.FilledBox.Dense.
How can I create a dense variant of TextField in Compose?
Starting with 1.2.0-alpha04 you can use the TextFieldDecorationBox together with BasicTextField to build a custom text field based on Material Design text fields.
To create a dense text field, use contentPadding parameter to decrease the paddings around the input field.
Something like:
var text by remember { mutableStateOf("") }
val singleLine = true
val enabled = true
val interactionSource = remember { MutableInteractionSource() }
BasicTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier
.indicatorLine(enabled, false, interactionSource, TextFieldDefaults.textFieldColors())
.background(
TextFieldDefaults.textFieldColors().backgroundColor(enabled).value,
TextFieldDefaults.TextFieldShape
)
.width(TextFieldDefaults.MinWidth),
singleLine = singleLine,
interactionSource = interactionSource
) { innerTextField ->
TextFieldDecorationBox(
value = text,
innerTextField = innerTextField,
enabled = enabled,
singleLine = singleLine,
visualTransformation = VisualTransformation.None,
interactionSource = interactionSource,
label = { Text("Label") },
contentPadding = TextFieldDefaults.textFieldWithLabelPadding(
start = 4.dp,
end = 4.dp,
bottom = 4.dp // make it dense
)
)
}

Categories

Resources