TextMeasurer: vad är det och hur fungerar textmätning i Compose

Författare: IT Sectr Publicerad: 2026-07-25 Lästid: 8 min

TextMeasurer — är ett API från Jetpack Compose avsett för att mäta textdimensioner innan den faktiska renderingen på skärmen. Till skillnad från den klassiska metoden via Paint.measureText i Android View, tillhandahåller TextMeasurer ett Compose-nativt sätt att få bredd, höjd och radmetrik med hänsyn till stil och begränsningar. Enligt Android Developers Documentation (2025) används TextMeasurer aktivt i anpassade Layout-komponenter, animerade bildtexter och adaptiva UI-element, där textstorleken påverkar positioneringen av andra element.

Huvudpunkter

  • TextMeasurer — Compose-API för att mäta text före rendering.
  • Metoden measure() returnerar TextLayoutResult med metrik för rader och tecken.
  • API:et tar hänsyn till stil, typsnitt, storlek och containerbegränsningar i pixlar.
  • TextMeasurer stöder mätning av en rad och text med flera rader.
  • Mätresultatet används för anpassad layout och textanimation.

Vad är TextMeasurer i Jetpack Compose?

TextMeasurer — är ett funktionellt gränssnitt från paketet androidx.compose.ui.text som gör det möjligt att mäta text i Compose utan direkt rendering på skärmen. Det är en del av Compose textmotor och arbetar på Paragraph API-nivå som använder Skia för rendering.

Huvudsyftet med TextMeasurer är förebyggande mätning. I Compose bestäms textstorleken vanligtvis efter att Composable redan har placerats i Layout. Men det finns scenarier där du behöver veta textbredden före kompositionen: till exempel för att avgöra om en rad får plats i containern, eller för att beräkna knappstorleken baserat på textlängden.

TextMeasurer löser detta problem genom att tillhandahålla metoden measure(), som tar emot TextMeasureRequest (text, stil, begränsningar) och returnerar TextLayoutResult (metrik, rader, tecken). Detta gör att utvecklaren kan få all data om texten synkront, utan en bildrutas fördröjning.

Använd TextMeasurer när textstorleken påverkar storleken på den överordnade komponenten, när du skapar animerade textövergångar eller när du implementerar anpassade Layout:er där text ligger intill andra element.

Hur fungerar TextMeasurer

TextMeasurer API består av två nyckelenheter: rememberTextMeasurer() (skapande av instans) och measure() (start av mätning). Instansen skapas en gång för komponentens hela livscykel och återanvänds för alla mätningar.

kotlin
val textMeasurer = rememberTextMeasurer()

val result = textMeasurer.measure(
    text = "Hello, Compose!",
    style = MaterialTheme.typography.bodyLarge,
    constraints = Constraints(maxWidth = 200, maxHeight = 50)
)

// resultatets bredd, resultatets höjd, antal rader

Parametern constraints bestämmer den maximala bredden och höjden inom vilken texten måste få plats. Om texten inte får plats på bredden flyttas den till nästa rad. Mätresultatet innehåller TextLayoutResult, där du kan få antalet rader, positionen för varje tecken, bredden på varje rad och den totala textstorleken.

TextMeasurer arbetar synkront i UI-tråden och orsakar inte omkomposition. Dock kan frekvent mätning av text med olika stilar skapa belastning — därför skapas instansen via remember och återanvänds.

Mäta en rad text

Det enklaste scenariot — mät bredden på enradig text för att bestämma storleken på den överordnade containern. Till exempel för en knapp vars bredd beror på etikettens längd.

kotlin
val textMeasurer = rememberTextMeasurer()
var label by remember { mutableStateOf("Submit") }

val textResult = remember(label) {
    textMeasurer.measure(
        text = label,
        style = MaterialTheme.typography.labelLarge,
        constraints = Constraints(maxWidth = 1000, maxHeight = 100)
    )
}

Box(
    modifier = Modifier
        .width(textResult.size.width.dp)
        .height(40.dp)
        .background(Color.Blue)
        .clickable { onClick() }
) {
    Text(text = label, style = MaterialTheme.typography.labelLarge)
}

I detta exempel garanterar remember(label) att mätningen endast startas om när texten ändras. Constraints är inställda med en stor maxWidth (1000) för att förhindra radbrytning — den faktiska begränsningen kommer att vara lika med textens bredd. Boxens bredd ställs in på den uppmätta textbredden, vilket ger effekten "knapp efter textstorlek".

Observera: bredden från resultatet måste konverteras till dp via .dp, eftersom TextMeasurer returnerar mått i pixlar, medan Modifier.width förväntar sig Dp. För noggrannhet, använd density och LocalDensity.current.

Mäta text med flera rader

För text med flera rader gör TextMeasurer det möjligt att bestämma inte bara den totala höjden, utan också antalet rader och positionen för varje tecken inom stycket. Detta är nödvändigt när du skapar anpassade textfält, chattar eller redigerare.

Huvudegenskaperna för TextLayoutResult för text med flera rader: lineCount (antal rader), getLineTop(index) (Y-koordinat för radens början), getLineBottom(index) (Y-koordinat för slutet), getLineWidth(index) (radbredd). Genom att kombinera dem kan du exakt positionera gränssnittselement i förhållande till textrader.

kotlin
val textMeasurer = rememberTextMeasurer()
val result = textMeasurer.measure(
    text = "Long multiline text that needs to be measured before layout",
    style = MaterialTheme.typography.bodyMedium,
    constraints = Constraints(maxWidth = 150, maxHeight = 300)
)

val linesCount = result.lineCount
val firstLineWidth = result.getLineWidth(0)
val totalHeight = result.size.height

Metoden getLineWidth(lineIndex) returnerar bredden på den angivna raden i pixlar. Den kan vara mindre än maxWidth om raden inte når containergränsen. Genom att känna till bredden på varje rad kan du manuellt implementera en justeringseffekt eller placera inline-element bredvid korta rader.

För att få positionen för ett specifikt tecken, använd getBoundingBox(offset), som returnerar en Rect med koordinaterna left, top, right, bottom. Detta är användbart för att positionera markören i anpassade textfält eller för att markera ett textområde med animation.

TextMeasurer i anpassade komponenter

Det mest kraftfulla användningsscenariot för TextMeasurer — anpassade Layout-komponenter, där text ligger intill andra element och deras storlekar är ömsesidigt beroende. Till exempel widgeten "Ikon + text", där ikonen ska centreras i förhållande till den första textraden, inte hela blocket.

I en standardrad centreras ikonen efter höjden på hela raden, vilket ser onaturligt ut när texten tar upp 3 rader och ikonen en. Med TextMeasurer kan du mäta den första raden och justera ikonen exakt i förhållande till den.

kotlin
val textMeasurer = rememberTextMeasurer()

Layout(
    content = {
        Icon(imageVector = Icons.Default.Star, contentDescription = null)
        Text(text = "Text med flera rader här")
    },
    measurePolicy = { measurables, constraints ->
        val textMeasurable = measurables[1]
        val textPlaceable = textMeasurable.measure(constraints)
        val iconPlaceable = measurables[0].measure(constraints)

        val firstLineHeight = textMeasurer.measure(
            text = "Sample",
            style = MaterialTheme.typography.bodyMedium,
            constraints = Constraints(maxWidth = 2000, maxHeight = 100)
        ).size.height

        layout(width = textPlaceable.width + iconPlaceable.width,
               height = maxOf(textPlaceable.height, iconPlaceable.height)) {
            iconPlaceable.placeRelative(0, (firstLineHeight - iconPlaceable.height) / 2)
            textPlaceable.placeRelative(iconPlaceable.width, 0)
        }
    }
)

I detta exempel bestämmer mätningen av den första raden via TextMeasurer ikonens position. Utan TextMeasurer skulle ikonen centreras över hela höjden av texten med flera rader, vilket är visuellt felaktigt. Detta mönster används brett i chattar, kontaktlistor och informationskort.

Prestandatips

TextMeasurer — är ett synkront API som arbetar i UI-tråden. Vid överdriven användning kan det orsaka bildrutefall, särskilt vid mätning av stora textvolymer på svagare enheter.

Första regeln — cachelagra resultatet. Linda alltid anropet till measure() i remember med beroenden av text och stil. Anropa aldrig measure() inuti CompositionLocal eller på heta omkompositionsvägar.

Andra regeln — begränsa maxWidth och maxHeight. Om du ställer in maxWidth = Constraints.Infinity kan TextMeasurer inte bryta rader och texten kommer att gå utanför skärmen. Skicka alltid realistiska begränsningar, särskilt för text med flera rader.

Tredje — undvik upprepad mätning med samma parametrar. Om texten och stilen inte har ändrats kommer resultatet av measure() att vara detsamma. Kombinera mätning med Deferred eller LaunchedEffect för asynkrona scenarier.

Vanliga frågor

Vad skiljer TextMeasurer från onSizeChanged i Compose?

TextMeasurer mäter text före rendering, medan onSizeChanged mäter efter. TextMeasurer behövs när textstorleken påverkar förälderns layout; onSizeChanged är lämplig för reaktiv logik efter komposition.

Kan SpannableString mätas via TextMeasurer?

Ja, TextMeasurer.measure() accepterar AnnotatedString som inkluderar SpannableString med inline-stilar, länkar och färger. Alla spans beaktas vid mätning.

Varför returnerar TextMeasurer storlek i pixlar, inte i dp?

TextMeasurer arbetar på Skia-renderingsnivå, där alla mått är i pixlar. Konvertera via LocalDensity.current: density.run { width.toDp() }.

Hur mäter man text innan teckensnittet laddas?

TextMeasurer använder FontFamily.Default tills det anpassade teckensnittet har laddats. För noggrann mätning, vänta på laddning via FontResource och använd async/await.

Påverkar TextMeasurer prestandan för LazyColumn-listor?

Mätning av text i varje element i LazyColumn kan minska FPS på svagare enheter. Optimering: cachelagra resultatet via remember och begränsa textstorleken.

Sammanfattning

  • TextMeasurer — Compose-API för att mäta text före rendering, returnerar TextLayoutResult.
  • Metoden measure() tar emot text, stil och Constraints i pixlar.
  • Instansen skapas via rememberTextMeasurer() och återanvänds.
  • För enradig text används resultatet för adaptiv containerbredd.
  • För text med flera rader — lineCount, getLineWidth() och getBoundingBox() ger en fullständig bild.
  • I anpassade Layout:er gör TextMeasurer det möjligt att justera element efter textens första rad.
  • Cachelagra resultatet via remember och undvik mätning på heta omkompositionsvägar.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också