I want to display a Text
inside a Card
with some inner padding and sometimes the text will not fit in. I want this thing to be marked with an ellipsis. But I can't make it work without maxLines
.
@Composable
fun CardWithText() {
Card(
modifier = Modifier
.height(60.dp)
.width(100.dp)
.border(1.dp, Color.Black, RoundedCornerShape(0))
) {
Card(
modifier = Modifier
.padding(8.dp)
.fillMaxSize()
.border(1.dp, Color.Black, RoundedCornerShape(0))
) {
Text(
text = "One two three four five six seven eight nine ten eleven twelve",
maxLines = 2,
overflow = TextOverflow.Ellipsis,
color = Color.Black
)
}
}
}
With maxLines = 2
With maxLines = 3
or not using maxLines
at all
CodePudding user response:
This is a known issue, causing Ellipsis
to ignore parent size constraints. Star it to bring more attention and follow the updates.
Meanwhile you can use this hacky solution: it'll calculate the real number of lines and pass the correct value for maxLines
:
@Composable
fun TextEllipsisFixed(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
onTextLayout: (TextLayoutResult) -> Unit,
style: TextStyle = LocalTextStyle.current,
) {
SubcomposeLayout(modifier = modifier) { constraints ->
var slotId = 0
fun placeText(
text: String,
onTextLayout: (TextLayoutResult) -> Unit,
constraints: Constraints,
maxLines: Int,
) = subcompose(slotId ) {
Text(
text = text,
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
softWrap = softWrap,
onTextLayout = onTextLayout,
style = style,
overflow = TextOverflow.Ellipsis,
maxLines = maxLines,
)
}[0].measure(constraints)
var textLayoutResult: TextLayoutResult? = null
val initialPlaceable = placeText(
text = text,
constraints = constraints,
onTextLayout = {
textLayoutResult = it
},
maxLines = maxLines,
)
val finalPlaceable = textLayoutResult?.let { layoutResult ->
if (!layoutResult.didOverflowHeight) return@let initialPlaceable
val lastVisibleLine = (0 until layoutResult.lineCount)
.last {
layoutResult.getLineBottom(it) <= layoutResult.size.height
}
placeText(
text = text,
constraints = constraints,
onTextLayout = onTextLayout,
maxLines = lastVisibleLine 1,
)
} ?: initialPlaceable
layout(
width = finalPlaceable.width,
height = finalPlaceable.height
) {
finalPlaceable.place(0, 0)
}
}
}
Usage:
Card(
modifier = Modifier
.height(60.dp)
.width(100.dp)
.border(1.dp, Color.Black, RoundedCornerShape(0))
) {
Card(
modifier = Modifier
.padding(8.dp)
.fillMaxSize()
.border(1.dp, Color.Black, RoundedCornerShape(0))
) {
TextEllipsisFixed(
text = "One two three four five six seven eight nine ten eleven twelve",
color = Color.Black
)
}
}
Result: