TextMeasurer হল Jetpack Compose-এর একটি API যা স্ক্রিনে প্রকৃত রেন্ডারিংয়ের আগে টেক্সটের মাত্রা মাপার জন্য ডিজাইন করা হয়েছে। Android View-এ Paint.measureText-এর মাধ্যমে ক্লাসিক পদ্ধতির বিপরীতে, TextMeasurer শৈলী এবং সীমাবদ্ধতা বিবেচনায় নিয়ে প্রস্থ, উচ্চতা এবং লাইন মেট্রিক্স পাওয়ার একটি Compose-নেটিভ উপায় প্রদান করে। Android Developers Documentation (2025) অনুসারে, TextMeasurer সক্রিয়ভাবে কাস্টম Layout কম্পোনেন্ট, অ্যানিমেটেড লেবেল এবং অভিযোজিত UI উপাদানগুলিতে ব্যবহৃত হয় যেখানে টেক্সটের আকার অন্যান্য উপাদানের অবস্থান নির্ধারণকে প্রভাবিত করে।
মূল বিষয়
TextMeasurer হল androidx.compose.ui.text প্যাকেজের একটি কার্যকরী ইন্টারফেস যা স্ক্রিনে প্রকৃত রেন্ডার না করেই Compose-এ টেক্সট মাপতে দেয়। এটি Compose টেক্সট ইঞ্জিনের অংশ এবং Paragraph API স্তরে কাজ করে, যা রেন্ডারিংয়ের জন্য Skia ব্যবহার করে।
TextMeasurer-এর মূল উদ্দেশ্য হল পূর্ব-মাপা। Compose-এ, টেক্সটের আকার সাধারণত Composable Layout-এ স্থাপন করার পরে নির্ধারিত হয়। কিন্তু এমন পরিস্থিতি রয়েছে যেখানে লেআউটের আগে টেক্সটের প্রস্থ জানা প্রয়োজন — উদাহরণস্বরূপ, একটি স্ট্রিং কন্টেইনারে ফিট কিনা তা সিদ্ধান্ত নেওয়া, বা টেক্সটের দৈর্ঘ্যের ভিত্তিতে বাটনের আকার গণনা করা।
TextMeasurer measure() পদ্ধতি প্রদান করে এই সমস্যার সমাধান করে, যা TextMeasureRequest (টেক্সট, শৈলী, সীমাবদ্ধতা) নেয় এবং TextLayoutResult (মেট্রিক্স, লাইন, অক্ষর) ফেরত দেয়। এটি ডেভেলপারকে এক ফ্রেমের বিলম্ব ছাড়াই সমস্ত টেক্সট ডেটা সিঙ্ক্রোনাসভাবে পেতে দেয়।
TextMeasurer ব্যবহার করুন যখন টেক্সটের আকার প্যারেন্ট কম্পোনেন্টের আকারকে প্রভাবিত করে, অ্যানিমেটেড টেক্সট ট্রানজিশন তৈরি করার সময়, বা কাস্টম Layout বাস্তবায়ন করার সময় যেখানে টেক্সট অন্যান্য উপাদানের সাথে সহাবস্থান করে।
TextMeasurer API দুটি মূল সত্তা নিয়ে গঠিত: rememberTextMeasurer() (ইনস্ট্যান্স তৈরি) এবং measure() (মাপা চালানো)। ইনস্ট্যান্সটি পুরো কম্পোনেন্ট জীবনচক্রের জন্য একবার তৈরি হয় এবং সমস্ত মাপার জন্য পুনরায় ব্যবহার করা হয়।
val textMeasurer = rememberTextMeasurer()
val result = textMeasurer.measure(
text = "Hello, Compose!",
style = MaterialTheme.typography.bodyLarge,
constraints = Constraints(maxWidth = 200, maxHeight = 50)
)
// result.size.width, result.size.height, result.lineCount
constraints প্যারামিটার সর্বোচ্চ প্রস্থ এবং উচ্চতা নির্ধারণ করে যার মধ্যে টেক্সট ফিট হওয়া উচিত। যদি টেক্সট প্রস্থে ফিট না হয়, তবে এটি পরবর্তী লাইনে চলে যায়। মাপার ফলাফলে TextLayoutResult থাকে, যা লাইনের সংখ্যা, প্রতিটি অক্ষরের অবস্থান, প্রতিটি লাইনের প্রস্থ এবং সামগ্রিক টেক্সট আকার প্রদান করে।
TextMeasurer UI থ্রেডে সিঙ্ক্রোনাসভাবে কাজ করে এবং পুনর্গঠন ট্রিগার করে না। তবে, বিভিন্ন শৈলীর সাথে ঘন ঘন টেক্সট মাপা ওভারহেড তৈরি করতে পারে — তাই ইনস্ট্যান্সটি remember-এর মাধ্যমে তৈরি এবং পুনরায় ব্যবহার করা হয়।
সবচেয়ে সহজ পরিস্থিতি হল প্যারেন্ট কন্টেইনারের আকার নির্ধারণের জন্য একক-লাইন টেক্সট-এর প্রস্থ মাপা। উদাহরণস্বরূপ, একটি বাটন যার প্রস্থ লেবেলের দৈর্ঘ্যের উপর নির্ভর করে।
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)
}
এই উদাহরণে, remember(label) নিশ্চিত করে যে টেক্সট পরিবর্তন হলেই কেবল মাপা পুনরায় শুরু হয়। লাইন র্যাপিং প্রতিরোধ করতে বড় maxWidth (1000) দিয়ে সীমাবদ্ধতা সেট করা হয়েছে — প্রকৃত সীমাবদ্ধতা টেক্সটের প্রস্থের সমান হবে। Box-এর প্রস্থ মাপা টেক্সট প্রস্থের সমান সেট করা হয়েছে, যা “টেক্সটের আকারের বাটন” প্রভাব দেয়।
নোট: ফলাফল থেকে প্রস্থ .dp-এর মাধ্যমে dp-তে রূপান্তর করতে হবে, কারণ TextMeasurer পিক্সেলে মাত্রা ফেরত দেয়, যখন Modifier.width Dp আশা করে। নির্ভুলতার জন্য, density এবং LocalDensity.current ব্যবহার করুন।
মাল্টি-লাইন টেক্সটের জন্য, TextMeasurer শুধুমাত্র মোট উচ্চতাই নয় বরং লাইনের সংখ্যা এবং অনুচ্ছেদের মধ্যে প্রতিটি অক্ষরের অবস্থান নির্ধারণ করতে দেয়। এটি কাস্টম টেক্সট ফিল্ড, চ্যাট বা এডিটর তৈরি করার সময় প্রয়োজনীয়।
মাল্টি-লাইন টেক্সটের জন্য প্রধান TextLayoutResult বৈশিষ্ট্য: lineCount (লাইনের সংখ্যা), getLineTop(index) (লাইন শুরুর Y-স্থানাঙ্ক), getLineBottom(index) (লাইন শেষের Y-স্থানাঙ্ক), getLineWidth(index) (লাইনের প্রস্থ)। এগুলি একত্রিত করে, আপনি টেক্সট লাইনের সাপেক্ষে ইন্টারফেস উপাদানগুলিকে সঠিকভাবে অবস্থান করতে পারেন।
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) পদ্ধতি নির্দিষ্ট লাইনের প্রস্থ পিক্সেলে ফেরত দেয়। লাইনটি কন্টেইনারের সীমানায় না পৌঁছালে এটি maxWidth-এর থেকে কম হতে পারে। প্রতিটি লাইনের প্রস্থ জেনে, আপনি ম্যানুয়ালি জাস্টিফাই প্রভাব বাস্তবায়ন করতে পারেন বা ছোট লাইনের পাশে ইনলাইন উপাদান স্থাপন করতে পারেন।
একটি নির্দিষ্ট অক্ষরের অবস্থান পেতে, getBoundingBox(offset) ব্যবহার করুন, যা left, top, right, bottom স্থানাঙ্ক সহ Rect ফেরত দেয়। এটি কাস্টম টেক্সট ফিল্ডে কার্সার অবস্থান নির্ধারণ বা অ্যানিমেশন সহ টেক্সট রেঞ্জ হাইলাইট করার জন্য দরকারী।
TextMeasurer-এর সবচেয়ে শক্তিশালী প্রয়োগ হল কাস্টম Layout কম্পোনেন্ট, যেখানে টেক্সট অন্যান্য উপাদানের সাথে সহাবস্থান করে এবং তাদের আকার পরস্পর নির্ভরশীল। উদাহরণস্বরূপ, একটি “আইকন + টেক্সট” উইজেট যেখানে আইকনটি পুরো ব্লকের পরিবর্তে টেক্সটের প্রথম লাইনের সাপেক্ষে কেন্দ্রীভূত হওয়া উচিত।
একটি স্ট্যান্ডার্ড Row-এ, আইকনটি পুরো Row-এর উচ্চতা দ্বারা কেন্দ্রীভূত হয়, যা অস্বাভাবিক দেখায় যখন টেক্সট 3 লাইন নেয় কিন্তু আইকনটি একটি। TextMeasurer-এর সাহায্যে, আপনি প্রথম লাইনটি মাপতে পারেন এবং আইকনটিকে সঠিকভাবে এর সাথে সারিবদ্ধ করতে পারেন।
val textMeasurer = rememberTextMeasurer()
Layout(
content = {
Icon(imageVector = Icons.Default.Star, contentDescription = null)
Text(text = "Multi-line text here")
},
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)
}
}
)
এই উদাহরণে, TextMeasurer-এর মাধ্যমে প্রথম লাইন মাপা আইকনের অবস্থান নির্ধারণ করে। TextMeasurer ছাড়া, আইকনটি মাল্টি-লাইন টেক্সটের পুরো উচ্চতা দ্বারা কেন্দ্রীভূত হবে, যা দৃশ্যত ভুল। এই প্যাটার্নটি চ্যাট, যোগাযোগ তালিকা এবং তথ্য কার্ডে ব্যাপকভাবে ব্যবহৃত হয়।
TextMeasurer একটি সিঙ্ক্রোনাস API যা UI থ্রেডে চলে। অত্যধিক ব্যবহারের ফলে ফ্রেম ড্রপ হতে পারে, বিশেষ করে দুর্বল ডিভাইসে বড় টেক্সট ভলিউম মাপার সময়।
প্রথম নিয়ম — ফলাফল ক্যাশ করুন. সর্বদা measure() কলটি টেক্সট এবং শৈলী নির্ভরতা সহ remember-এ মোড়ান। CompositionLocal-এর ভিতরে বা হট পুনর্গঠন পথে কখনও measure() কল করবেন না।
দ্বিতীয় নিয়ম — maxWidth এবং maxHeight সীমিত করুন। যদি আপনি maxWidth = Constraints.Infinity সেট করেন, TextMeasurer লাইন র্যাপ করতে পারবে না এবং টেক্সট স্ক্রিনের বাইরে চলে যাবে। সর্বদা বাস্তবসম্মত সীমাবদ্ধতা পাস করুন, বিশেষ করে মাল্টি-লাইন টেক্সটের জন্য।
তৃতীয় নিয়ম — একই প্যারামিটার দিয়ে বারবার মাপা এড়িয়ে চলুন। যদি টেক্সট এবং শৈলী পরিবর্তিত না হয়, measure()-এর ফলাফল একই হবে। অ্যাসিঙ্ক্রোনাস পরিস্থিতির জন্য Deferred বা LaunchedEffect-এর সাথে মাপা একত্রিত করুন।
সচরাচর জিজ্ঞাসা
TextMeasurer রেন্ডারিংয়ের আগে টেক্সট মাপে, যখন onSizeChanged পরে মাপে। TextMeasurer প্রয়োজন যখন টেক্সটের আকার প্যারেন্ট লেআউটকে প্রভাবিত করে; onSizeChanged কম্পোজিশনের পরে প্রতিক্রিয়াশীল লজিকের জন্য কাজ করে।
হ্যাঁ, TextMeasurer.measure() AnnotatedString গ্রহণ করে, যার মধ্যে ইনলাইন শৈলী, লিংক এবং রঙ সহ SpannableString অন্তর্ভুক্ত। মাপার সময় সমস্ত স্প্যান বিবেচনায় নেওয়া হয়।
TextMeasurer Skia রেন্ডারিং স্তরে কাজ করে, যেখানে সমস্ত মাত্রা পিক্সেলে থাকে। LocalDensity.current-এর মাধ্যমে রূপান্তর করুন: density.run { width.toDp() }.
TextMeasurer কাস্টম ফন্ট লোড না হওয়া পর্যন্ত FontFamily.Default ব্যবহার করে। সঠিক মাপার জন্য, FontResource-এর মাধ্যমে ফন্ট লোড হওয়ার জন্য অপেক্ষা করুন এবং async/await ব্যবহার করুন।
প্রতিটি LazyColumn আইটেমে টেক্সট মাপা দুর্বল ডিভাইসে FPS কমাতে পারে। অপ্টিমাইজেশন: remember-এর মাধ্যমে ফলাফল ক্যাশ করুন এবং টেক্সটের আকার সীমিত করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন