I have custom total textfield like this
Where 1 - textfield component outline; 2 - inner textfield ouline; 3 - trailing icon or suffix (for material 3 component)
As you can see, the inner text box has a starting extra border and an ending extra border. It fill whole legth of textfiled component now.
I would like to make like this (some kind of "wrap_content" for inner textfield):
Is there any way to customize the inner borders of BaseTextField or do I need to dive deep into Compose and create my own textbox from scratch?
My TotalTextField code:
@Composable
private fun TotalOutlinedTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = LocalTextStyle.current,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
singleLine: Boolean = false,
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
minLines: Int = 1,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape = MaterialTheme.shapes.small,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) {
val textColor = textStyle.color.takeOrElse {
colors.textColor(enabled).value
}
val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
@OptIn(ExperimentalMaterialApi::class)
BasicTextField(
value = value,
modifier = if (label != null) {
modifier.semantics(mergeDescendants = true) {}
} else {
modifier
}
.background(colors.backgroundColor(enabled).value, shape)
.defaultMinSize(
minWidth = TextFieldDefaults.MinWidth,
minHeight = TextFieldDefaults.MinHeight
),
onValueChange = onValueChange,
enabled = enabled,
readOnly = readOnly,
textStyle = mergedTextStyle,
cursorBrush = SolidColor(colors.cursorColor(isError).value),
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
interactionSource = interactionSource,
singleLine = singleLine,
maxLines = maxLines,
minLines = minLines,
decorationBox = @Composable { innerTextField ->
TextFieldDefaults.OutlinedTextFieldDecorationBox(
value = value,
visualTransformation = visualTransformation,
innerTextField = innerTextField,
placeholder = placeholder,
label = label,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
singleLine = singleLine,
enabled = enabled,
isError = isError,
interactionSource = interactionSource,
colors = colors,
border = {
TextFieldDefaults.BorderBox(
enabled,
isError,
interactionSource,
colors,
shape
)
},
contentPadding = textFieldWithoutLabelPadding(
top = PADDING_8.dp,
bottom = PADDING_8.dp,
)
)
}
)
}
Going through the source code of TextField
,
In internal fun TextFieldLayout
, we can see that the prefix
, suffix
, leading
, and trailing
are all placed inside a Layout
by calculating placement internally. There are no direct options to override them from the component level.
To achieve the given UI,
You can use a Row
with the required background color and have the BasicTextField
and the trailing composable as children and align them as required.
Sample code
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.background(Color.Companion.LightGray) // TextField background color
.defaultMinSize(
TextFieldDefaults.MinWidth,
TextFieldDefaults.MinHeight,
),
) {
BasicTextField(
modifier = modifier.width(IntrinsicSize.Min),
... // Properties
)
trailingIcon?.invoke()
}