Search code examples
android-jetpack-composetext-sizeandroid-compose-textfield

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?


Solution

  • 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}"
                    )
    
                },
            )
        }
    }