I try to use OutlinedTextFieldDefaults.DecorationBox
to achieve such an effect: a frame surrounded by OutlinedTextField
border style, which can accommodate any compose component inside. But when I tried to implement it, I found that the position of label was incorrect. I am not sure which parameter is affected by this. I'd like to fix this so that the label is in the correct position, or use another method to achieve a similar effect.
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
fun ShowTagArea (
paddingValue: PaddingValues,
showTags: List<Tag>,
isSelected: Boolean,
) {
OutlinedTextFieldDefaults.DecorationBox(
contentPadding = paddingValue,
value = "value",
innerTextField = {
Box(
modifier = Modifier
.fillMaxWidth()
) {
FlowRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
.padding(10.dp)
.fillMaxWidth()
) {
showTags.forEach { tag ->
FilterChip(
selected = isSelected,
onClick = {},
label = { Text(text = tag.tagName) },
)
}
}
}
},
singleLine = true,
enabled = true,
label = { Text("Label") },
placeholder = {},
visualTransformation = VisualTransformation.None,
interactionSource = remember { MutableInteractionSource() },
colors = OutlinedTextFieldDefaults.colors(),
container = {
OutlinedTextFieldDefaults.Container(
modifier = Modifier.padding(paddingValue),
enabled = true,
isError = false,
interactionSource = remember { MutableInteractionSource() },
)
}
)
}
@Composable
@Preview(showBackground = true)
fun FileDetailView() {
LazyColumn (
modifier = Modifier.fillMaxWidth()
) {
item {
OutlinedTextField(
value = "2023.6.10 10:10:10",
label = { Text(text = "Latest Modify Time") },
onValueChange = {},
readOnly = true,
modifier = Modifier.fillMaxWidth().padding(5.dp)
)
}
item {
ShowTagArea(
paddingValue = PaddingValues(5.dp),
showTags = data.tags,
isSelected = true
)
}
}
}
I expected that label will be aligned with "Latest Modify Time" label.
Wrap DecorationBox
in a Box
and apply paddingValue
to that Box
instead of anywhere inside of the DecorationBox
:
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
private fun ShowTagArea(
paddingValue: PaddingValues,
showTags: List<Tag>,
isSelected: Boolean,
) {
Box(
modifier = Modifier.padding(paddingValue)
) {
OutlinedTextFieldDefaults.DecorationBox(
// contentPadding = paddingValue,
value = "value",
innerTextField = {
Box(
modifier = Modifier
.fillMaxWidth()
) {
FlowRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
// .padding(10.dp)
.fillMaxWidth()
) {
showTags.forEach { tag ->
FilterChip(
selected = isSelected,
onClick = {},
label = { Text(text = tag.tagName) },
)
}
}
}
},
singleLine = true,
enabled = true,
label = { Text("Label") },
placeholder = {},
visualTransformation = VisualTransformation.None,
interactionSource = remember { MutableInteractionSource() },
colors = OutlinedTextFieldDefaults.colors(),
container = {
OutlinedTextFieldDefaults.Container(
// modifier = Modifier.padding(paddingValue),
enabled = true,
isError = false,
interactionSource = remember { MutableInteractionSource() },
)
}
)
}
}
Edit:
Alternatively, do not add any padding to the individual items, set padding and vertical spacing for the LazyColumn
instead :
LazyColumn(
contentPadding = PaddingValues(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
Explanation:
The reason for label
being misaligned with the border is the padding being added to OutlinedTextFieldDefaults.Container
. That container is essentially is a Box
with a border, so padding
adds space along the border only and doesn't affect label.
There is also no reason to set contentPadding
parameter of DecorationBox
. This parameter has default value by the m3 specs and it also affects the label cutout position, better leave it as it is. I have also removed FlowRow
padding because there is padding around it already (contentPadding
param).
After all those paddings removed, the label is aligned with the border, but there is no padding around ShowTagArea
and there is no modifier
parameter in DecorationBox
to add padding. We can fix it by wrapping DecorationBox
in a layout composable like Box
and adding padding
to this container. Or we could let the outer container (LazyColumn
) handle all the spacing and padding for us.