I have a Text component that I want the width to expand as big as it wants to accommodate the supplied text and to be exactly 2 lines tall.

I have attempted to implement this by calculating the height using my font size and the number of lines that I want:

val textHeight = textStyle.lineHeight.value * 2

Then, based on various articles (such as this one https://www.answertopia.com/jetpack-compose/jetpack-compose-intrinsicsize-tutorial/) and what I understand of IntrinsicSize, shouldn't I be able to constrain the height and use IntrinsicSize.Min to set the text's width to fit everything at the minimum width required? This actually just cuts off the text.

Text(
    modifier = Modifier.height(textHeight).width(IntrinsicSize.Min),
    text = "Fabrication et assemblage soignes",
    style = textStyle,
)

For some reason ends up rendering as

enter image description here

I want it to look like

Fabrication et 
assemblage soigne

On two lines, wrapped to the minimum width.

How can I achieve the result I want?

Also note using .wrapContentWidth() doesn't work because then the text just takes up 1 line and leaves the extra height space empty.

1

There are 1 answers

0
220284 On

If it's just for that specific text you want, which I highly doubt, you could insert a line break inside the string as follows: "Fabrication et\nassemblage soignes".

If it's for more general sentences, then it's not clear how you would want the Text component to distribute the words between the two lines.

Assuming you would want the width of the lines to be as close as possible (like this strategy), the most 'elegant' way I can think of (which is not very elegant) is implementing an algorithm which would measure the entire width of the text, find the whitespace closest to the middle and replace it with a line break.

I've implemented something simpler which does manage to divide at the position you want:

fun String.attemptToDivideEqually(): String {
    if (this.length <= 2) return this

    val idealLineBreakIndex = this.closestWhiteSpaceToIndex((this.length + 1) / 2) ?: return this

    return this.substring(0, idealLineBreakIndex) + "\n" + this.substring(
        idealLineBreakIndex + 1,
        this.length
    )
}

fun String.closestWhiteSpaceToIndex(index: Int): Int? {
    if (index !in 0 .. this.lastIndex) return null
    val maxDistance = maxOf(index, this.lastIndex - index)

    for (i in 0 .. maxDistance) {
        if (index + i <= this.lastIndex && this[index + i] == ' ') return index + i
        if (index - i >= 0 && this[index - i] == ' ') return index - i
    }
    return null
}

However, I don't recommend using it in production code for the following reasons:

  1. Characters can differ greatly in width, so if for whatever reason, the first 'half' of the string has significantly more 'narrow' letters, than the latter, it may look odd.
  2. If there are only a few number of words, it may look odd.
  3. There are probably more reasons I cannot currently think of + I have not tested it thoroughly.

It was an interesting question nonetheless!