Stuck
Stuck

Reputation: 13

TextMeasurer gives different results than the actual Text in Jetpack Compose

I'm trying to measure the number of lines of a Text without rendering it. I thought I could use a TextMeasurer, however the number of "measured" lines is different than the number of lines I get if I render the actual Text.

This is the code I'm using:

Box () {
    val textMeasurer = rememberTextMeasurer()
    val measuredLayoutResult = textMeasurer.measure(
        largeText)
    println("Measured lines: ${measuredLayoutResult.lineCount}, " +
            "Measured height: ${measuredLayoutResult.size.height}, " +
            "Measured width: ${measuredLayoutResult.size.width}")
    Text(
        largeText,
        onTextLayout = { textLayoutResult ->
            println("Actual lines: ${textLayoutResult.lineCount}, " +
                    "Actual height: ${textLayoutResult.size.height}, " +
                    "Actual width: ${textLayoutResult.size.width}")

        },
    )
}

I would expect the numbers to be the same, instead I'm getting the following: Measured lines: 25, Measured height: 1132, Measured width: 30154 Actual lines: 235, Actual height: 2088, Actual width: 1080

Any ideas what I am doing wrong?

Upvotes: 1

Views: 1376

Answers (2)

Thracian
Thracian

Reputation: 67248

When you don't assign constraints param to measure function of TextMeasurer it uses default Constraints with maxWidth and maxHeight with Constraints.Infinity.

@Stable
fun measure(
    text: String,
    style: TextStyle = TextStyle.Default,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    constraints: Constraints = Constraints(),
    layoutDirection: LayoutDirection = this.defaultLayoutDirection,
    density: Density = this.defaultDensity,
    fontFamilyResolver: FontFamily.Resolver = this.defaultFontFamilyResolver,
    skipCache: Boolean = false
)

Use a BoxWithConstraints and pass a Constraints from it to limit total width that text can be measured with

@Preview
@Composable
private fun Test() {

    val largeText =
        "some large tatasda sdasdasdsa dasdasd asda sdasd asdasd asdasdasdasdasdasdasdasdasd"
    BoxWithConstraints {

        val textMeasurer = rememberTextMeasurer()
        val measuredLayoutResult = textMeasurer.measure(
            constraints = constraints,
            text = largeText
        )
        println(
            "Measured lines: ${measuredLayoutResult.lineCount}, " +
                    "Measured height: ${measuredLayoutResult.size.height}, " +
                    "Measured width: ${measuredLayoutResult.size.width}"
        )
        Text(
            largeText,
            onTextLayout = { textLayoutResult ->
                println(
                    "Actual lines: ${textLayoutResult.lineCount}, " +
                            "Actual height: ${textLayoutResult.size.height}, " +
                            "Actual width: ${textLayoutResult.size.width}"
                )

            },
        )
    }
}

Upvotes: 0

BenjyTec
BenjyTec

Reputation: 10887

Make sure that you provide all text styling arguments that you applied to the Text Composable to the measure function too (in case you truncated the code you posted).

If the code you posted is the exact code you have, then my guess is that the Box with the TextMeasurer exceeds the screen, while the Text for some reason doesn't. According to the Box documentation,

The Box will size itself to fit the content, subject to the incoming constraints.

So you could try to define the size of the Box to fit the screen and see if the issue persists:

Box (modifier = Modifier.fillMaxSize()) {
    val textMeasurer = rememberTextMeasurer()
    val measuredLayoutResult = textMeasurer.measure(largeText)
    //...
}

Upvotes: 0

Related Questions