I want to set the ellipsis in the start of the text compose when the text is overflow like this picture below:
However, I did created with the ellipsis property of the compose. The result was not correct:
Here the code I tried:
// current week text
Box(
modifier = Modifier
.weight(1f)
.clip(RoundedCornerShape(dimensionResource(id = R.dimen.dp_6)))
.background(Color.White)
.padding(
vertical = dimensionResource(id = R.dimen.dp_8),
horizontal = dimensionResource(id = R.dimen.dp_10)
)
.singleClick(isShowClickEffect = false) {
onCurrentWeekTextTapped()
}
) {
Text(
text = currentWeekText,
style = LGAppTypography.mobileBodyMedium,
color = colorResource(id = R.color.Color_11161D),
fontWeight = FontWeight.W400,
maxLines = 1,
**overflow = TextOverflow.Ellipsis,**
)
}
Note! I did it for AppBar
By changing this code a bit
I got this:
@Composable
fun StartEllipsisText(
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,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current,
) {
val layoutText = remember(text) { "$text $ellipsisText" }
val textLayoutResultState = remember(layoutText) { mutableStateOf<TextLayoutResult?>(null) }
SubcomposeLayout(modifier) { constraints ->
subcompose("measure") {
Text(
text = layoutText,
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
softWrap = softWrap,
maxLines = 1,
onTextLayout = { textLayoutResultState.value = it },
style = style,
)
}.first().measure(Constraints())
val textLayoutResult =
textLayoutResultState.value ?: return@SubcomposeLayout layout(0, 0) {}
val placeable = subcompose("visible") {
val finalText = remember(text, textLayoutResult, constraints.maxWidth) {
if (
text.isEmpty() ||
textLayoutResult.getBoundingBox(text.indices.last).right <= constraints.maxWidth
) {
return@remember text
}
val ellipsisWidth = layoutText.indices.toList()
.takeLast(ellipsisCharactersCount)
.let widthLet@{ indices ->
for (i in indices) {
val width = textLayoutResult.getBoundingBox(i).width
if (width > 0) {
return@widthLet width * ellipsisCharactersCount
}
}
throw IllegalStateException("all ellipsis chars have invalid width")
}
val availableWidth = constraints.maxWidth - ellipsisWidth
val endCounter = BoundCounter(text, textLayoutResult) { text.indices.last - it }
while (availableWidth - endCounter.width > 0) {
val possibleEndWidth = endCounter.widthWithNextChar()
if (availableWidth - possibleEndWidth >= 0) {
endCounter.addNextChar()
} else {
break
}
}
ellipsisText + endCounter.string.reversed().trimStart()
}
Text(
text = finalText,
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
softWrap = softWrap,
onTextLayout = onTextLayout,
style = style,
)
}[0].measure(constraints)
layout(placeable.width, placeable.height) {
placeable.place(0, 0)
}
}
}
private const val ellipsisCharactersCount = 3
private const val ellipsisCharacter = '.'
private val ellipsisText =
List(ellipsisCharactersCount) { ellipsisCharacter }.joinToString(separator = "")
private class BoundCounter(
private val text: String,
private val textLayoutResult: TextLayoutResult,
private val charPosition: (Int) -> Int,
) {
var string = ""
private set
var width = 0f
private set
private var _nextCharWidth: Float? = null
private var invalidCharsCount = 0
fun widthWithNextChar(): Float =
width + nextCharWidth()
private fun nextCharWidth(): Float =
_nextCharWidth ?: run {
var boundingBox: Rect
invalidCharsCount--
do {
boundingBox = textLayoutResult
.getBoundingBox(charPosition(string.count() + ++invalidCharsCount))
} while (boundingBox.right == 0f)
_nextCharWidth = boundingBox.width
boundingBox.width
}
fun addNextChar() {
string += text[charPosition(string.count())]
width += nextCharWidth()
_nextCharWidth = null
}
}