TextMeasurer — bu ekranda haqiqiy renderlashdan oldin matn o'lchamlarini o'lchash uchun mo'ljallangan Jetpack Compose API-sidir. Android View-dagi Paint.measureText orqali klassik yondashuvdan farqli o'laroq, TextMeasurer uslub va cheklovlarni hisobga olgan holda matn kengligi, balandligi va qator metrikalarini olish uchun Compose-native usulini taqdim etadi. Android Developers Documentation (2025) ma'lumotlariga ko'ra, TextMeasurer maxsus Layout komponentlarida, animatsion sarlavhalarda va matn o'lchami boshqa elementlarning joylashishiga ta'sir qiladigan adaptiv UI elementlarida faol qo'llaniladi.
Asosiy ma'lumotlar
TextMeasurer — bu ekranda to'g'ridan-to'g'ri renderlamasdan Compose-da matnni o'lchash imkonini beruvchi androidx.compose.ui.text paketidagi funksional interfeysdir. U Compose matn dvigatelining bir qismi bo'lib, Skia-dan renderlash uchun foydalanadigan Paragraph API darajasida ishlaydi.
TextMeasurer-ning asosiy maqsadi oldindan o'lchashdir. Compose-da matn o'lchami odatda Composable Layout-ga joylashtirilgandan keyin aniqlanadi. Biroq, ba'zi stsenariylarda kompozitsiyadan oldin matn kengligini bilish kerak bo'ladi: masalan, qator konteynerga sig'ishini aniqlash yoki matn uzunligiga qarab tugma o'lchamini hisoblash.
TextMeasurer bu muammoni measure() metodi bilan hal qiladi. U TextMeasureRequest (matn, uslub, cheklovlar) qabul qiladi va TextLayoutResult (metrikalar, qatorlar, belgilar) qaytaradi. Bu dasturchiga bir kadr kechikishisiz matn haqidagi barcha ma'lumotlarni sinxron ravishda olish imkonini beradi.
TextMeasurer-dan matn o'lchami ota-komponentning o'lchamiga ta'sir qilganda, animatsion matn o'tishlarini yaratishda yoki matn boshqa elementlar bilan yonma-yon joylashgan maxsus Layout-larni amalga oshirishda foydalaning.
TextMeasurer API-si ikkita asosiy ob'ektdan iborat: rememberTextMeasurer() (namuna yaratish) va measure() (o'lchashni boshlash). Namuna komponentning butun hayot tsikli uchun bir marta yaratiladi va barcha o'lchashlar uchun qayta ishlatiladi.
val textMeasurer = rememberTextMeasurer()
val result = textMeasurer.measure(
text = "Hello, Compose!",
style = MaterialTheme.typography.bodyLarge,
constraints = Constraints(maxWidth = 200, maxHeight = 50)
)
// natija kengligi, natija balandligi, qatorlar soni
constraints parametri matn joylashishi kerak bo'lgan maksimal kenglik va balandlikni belgilaydi. Agar matn kenglikka sig'masa, u keyingi qatorga o'tkaziladi. O'lchash natijasi TextLayoutResult-ni o'z ichiga oladi, unda qatorlar soni, har bir belgining joylashuvi, har bir qatorning kengligi va matnning umumiy o'lchamini olish mumkin.
TextMeasurer UI oqimida sinxron ishlaydi va qayta kompozitsiyaga sabab bo'lmaydi. Biroq, matnni turli uslublar bilan tez-tez o'lchash yuk hosil qilishi mumkin — shuning uchun namuna remember orqali yaratiladi va qayta ishlatiladi.
Eng oddiy stsenariy — ota-konteyner o'lchamini aniqlash uchun bir qatorli matn kengligini o'lchash. Masalan, kengligi yorliq uzunligiga bog'liq bo'lgan tugma uchun.
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)
}
Ushbu misolda, remember(label) o'lchash faqat matn o'zgarganda qayta boshlanishini kafolatlaydi. Constraints qator o'tkazilishini oldini olish uchun katta maxWidth (1000) bilan o'rnatilgan — haqiqiy cheklov matn kengligiga teng bo'ladi. Box kengligi o'lchangan matn kengligiga o'rnatiladi, bu «matn o'lchamiga mos tugma» effektini beradi.
Diqqat: natijadagi kenglikni .dp orqali dp-ga aylantirish kerak, chunki TextMeasurer o'lchamlarni pikselda qaytaradi, Modifier.width esa Dp kutadi. Aniqlik uchun density va LocalDensity.current dan foydalaning.
Ko'p qatorli matn uchun TextMeasurer nafaqat umumiy balandlikni, balki qatorlar sonini va har bir belgining joylashuvini paragraf ichida aniqlash imkonini beradi. Bu maxsus matn maydonlari, chatlar yoki muharrirlarni yaratishda zarur.
Ko'p qatorli matn uchun TextLayoutResult-ning asosiy xususiyatlari: lineCount (qatorlar soni), getLineTop(index) (qator boshlanishining Y-koordinatasi), getLineBottom(index) (tugashining Y-koordinatasi), getLineWidth(index) (qator kengligi). Ularni birlashtirib, interfeys elementlarini matn qatorlariga nisbatan aniq joylashtirish mumkin.
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
getLineWidth(lineIndex) metodi ko'rsatilgan qatorning kengligini pikselda qaytaradi. Agar qator konteyner chegarasiga yetmasa, u maxWidth-dan kichik bo'lishi mumkin. Har bir qatorning kengligini bilgan holda, tekislash effektini qo'lda amalga oshirish yoki qisqa qatorlar yoniga inline elementlarni joylashtirish mumkin.
Muayyan belgining o'rnini olish uchun left, top, right, bottom koordinatalari bilan Rect qaytaradigan getBoundingBox(offset) dan foydalaning. Bu maxsus matn maydonlarida kursorni joylashtirish yoki animatsiya bilan matn oralig'ini ajratib ko'rsatish uchun foydali.
TextMeasurer-ning eng kuchli qo'llanish stsenariysi — matn boshqa elementlar bilan yonma-yon joylashgan va ularning o'lchamlari o'zaro bog'liq bo'lgan maxsus Layout komponentlaridir. Masalan, «Belgi + matn» vidjeti, bu yerda belgi butun blokka emas, balki matnning birinchi qatoriga nisbatan markazlashtirilishi kerak.
Standart Row-da belgi butun Row balandligi bo'yicha markazlashtiriladi, bu matn 3 qator, belgi esa bir qatorni egallaganda g'ayritabiiy ko'rinadi. TextMeasurer bilan birinchi qatorni o'lchash va belgini aynan unga nisbatan tekislash mumkin.
val textMeasurer = rememberTextMeasurer()
Layout(
content = {
Icon(imageVector = Icons.Default.Star, contentDescription = null)
Text(text = "Ko'p qatorli matn bu yerda")
},
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)
}
}
)
Ushbu misolda TextMeasurer orqali birinchi qatorni o'lchash belgining o'rnini aniqlaydi. TextMeasurer bo'lmasa, belgi ko'p qatorli matnning butun balandligi bo'yicha markazlashgan bo'lar edi, bu vizual jihatdan noto'g'ri. Ushbu naqsh chatlar, kontakt ro'yxatlari va axborot kartochkalarida keng qo'llaniladi.
TextMeasurer — UI oqimida ishlaydigan sinxron API. Haddan tashqari ishlatilganda, ayniqsa zaif qurilmalarda katta hajmdagi matnni o'lchashda kadr yo'qotilishiga sabab bo'lishi mumkin.
Birinchi qoida — natijani keshlang. Har doim measure() chaqiruvini matn va uslubga bog'liqliklar bilan remember-ga o'rab oling. Hech qachon measure() ni CompositionLocal ichida yoki recomposition-ning issiq yo'llarida chaqirmang.
Ikkinchi qoida — maxWidth va maxHeight-ni cheklang. Agar maxWidth = Constraints.Infinity o'rnatsangiz, TextMeasurer qatorlarni o'tkaza olmaydi va matn ekrandan chiqib ketadi. Har doim realistik cheklovlarni o'rnating, ayniqsa ko'p qatorli matn uchun.
Uchinchi — bir xil parametrlar bilan takroriy o'lchashdan saqlaning. Agar matn va uslub o'zgarmagan bo'lsa, measure() natijasi bir xil bo'ladi. Asinxron stsenariylar uchun o'lchashni Deferred yoki LaunchedEffect bilan birlashtiring.
Tez-tez so'raladigan savollar
TextMeasurer matnni renderlashdan oldin o'lchaydi, onSizeChanged esa keyin. TextMeasurer matn o'lchami ota-komponent layout-iga ta'sir qilganda kerak; onSizeChanged kompozitsiyadan keyin reaktiv mantiq uchun mos keladi.
Ha, TextMeasurer.measure() inline uslublar, havolalar va ranglar bilan SpannableString-ni o'z ichiga olgan AnnotatedString-ni qabul qiladi. Barcha spanlar o'lchashda hisobga olinadi.
TextMeasurer Skia-renderlash darajasida ishlaydi, bu erda barcha o'lchamlar pikselda. LocalDensity.current orqali aylantiring: density.run { width.toDp() }.
TextMeasurer maxsus shrift yuklanmaguncha FontFamily.Default dan foydalanadi. Aniq o'lchash uchun FontResource orqali yuklanishni kuting va async/await dan foydalaning.
LazyColumn-ning har bir elementida matnni o'lchash zaif qurilmalarda FPS-ni pasaytirishi mumkin. Optimallashtirish: natijani remember orqali keshlang va matn hajmini cheklang.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.