I want to make a list item which contains two texts , one anchored to the start of parent and one to the end of parent, I want the space to be dynamically handled each time and if too long it should wrap text and break line, my problem is that I'm using this item everywhere, sometimes Text1 takes up more space than Text2 and vice versa, this makes using Row with weight not useful, I tried using constraint layout, with top, bottom and start/end constraints, but this makes the texts overlap when too long.
This is my constraint layout approach:
val offset: Dp = 8.dp
val modifier = if (onClick != null) {
Modifier
.fillMaxWidth()
.background(backgroundColor)
.height(rowHeight)
.clickable(
onClick = onClick
)
} else {
Modifier
.fillMaxWidth(widthPercentage)
.background(backgroundColor)
.defaultMinSize(minHeight = rowHeight)
}
ConstraintLayout(
modifier = modifier
) {
val (titleRef, infoRef, disclosureRef) = createRefs()
Text(
text = title,
color = titleColor,
style = titleStyle,
modifier = Modifier
.constrainAs(titleRef) {
start.linkTo(parent.start, margin = horizontalPadding)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
}
)
Text(
text = infoText,
color = infoTextColor,
style = infoStyle,
textAlign = TextAlign.End,
modifier = Modifier
.constrainAs(infoRef) {
if (showDisclosure) {
end.linkTo(disclosureRef.start, margin = offset)
} else {
end.linkTo(parent.end, margin = horizontalPadding)
}
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
}
)
if (showDisclosure) {
Image(
painter = painterResource(id = R.drawable.ic_disclosure_gray),
modifier = Modifier
.constrainAs(disclosureRef) {
end.linkTo(parent.end, margin = horizontalPadding - offset)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
}
)
}
}
And the row approach which does not give me flexibility, when wanting different text having the bigger weight each time:
val offset: Dp = 8.dp
val modifier = if (onClick != null) {
Modifier
.defaultMinSize(minHeight = 35.dp)
.fillMaxWidth()
.background(backgroundColor)
.padding(vertical = verticalPadding)
.clickable(
onClick = onClick
)
} else {
Modifier
.fillMaxWidth(widthPercentage)
.background(backgroundColor)
.padding(vertical = verticalPadding)
.defaultMinSize(minHeight = rowHeight)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
) {
Text(
text = title,
color = titleColor,
style = titleStyle,
maxLines = 2,
modifier = Modifier
.weight(1f)
.padding(start = horizontalPadding)
)
val trailingPadding = if (showDisclosure) {
offset
} else {
horizontalPadding
}
Text(
text = infoText,
color = infoTextColor,
style = infoStyle,
textAlign = TextAlign.End,
modifier = Modifier
.weight(1.5f)
.padding(start = horizontalPadding, end = trailingPadding)
)
if (showDisclosure) {
Image(
painter = painterResource(id = R.drawable.ic_disclosure_gray),
modifier = Modifier
.padding(end = offset)
// .align(Alignment.CenterVertically)
)
}
}
What I am expecting :
Please try to apply the weight
Modifier to the first Text Composable as follows:
@Composable
fun MyComposable() {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
modifier = Modifier.weight(1f),
text = "ABC DEF"
)
Text(text = "1000 1000 1000 1000 1000 1000 1000 1000 1000")
}
}
Jetpack Compose measures the unweighted children first, then it distributes the remaining space between the children that have the weight
Modifier set.
The parent will divide the horizontal space remaining after measuring unweighted child elements and distribute it according to this weight.
Output:
Note that if the second Text might fill the whole screen width, you need to specify a max width of the second Text to prevent it from filling the whole screen width and pushing the first Text off. You can try this as follows:
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
modifier = Modifier.weight(1f),
text = "ABC DEF"
)
Text(
modifier = Modifier.widthIn(max = screenWidth - 150.dp), // first Text will always have 150dp space
Text(text = "1000 1000 1000 1000 1000 1000 1000 1000 1000")
)
}