Compose লেআউটে ইন্ট্রিনসিক পরিমাপ

Compose-এর একটি নিয়ম হল, আপনাকে চাইল্ড কম্পোজেবল একবারই পরিমাপ করতে হবে; চাইল্ড কম্পোজেবল দুবার পরিমাপ করলে রানটাইম এক্সেপশন থ্রো করে। তবে, এমন কিছু সময় আসে যখন আপনার সন্তানের পরিমাপ করার আগে তার সম্পর্কে কিছু তথ্য প্রয়োজন হয়।

Intrinsics আপনাকে চাইল্ড এলিমেন্টকে আসলে পরিমাপ করার আগে কোয়েরি করতে দেয়।

কম্পোজেবলকে আপনি IntrinsicSize.Min বা IntrinsicSize.Max-এর জন্য বলতে পারেন:

  • Modifier.width(IntrinsicSize.Min) - আপনার কন্টেন্ট সঠিকভাবে দেখানোর জন্য ন্যূনতম কত প্রস্থ প্রয়োজন?
  • Modifier.width(IntrinsicSize.Max) - আপনার কন্টেন্ট সঠিকভাবে দেখানোর জন্য সর্বাধিক কত প্রস্থ প্রয়োজন?
  • Modifier.height(IntrinsicSize.Min) - আপনার কন্টেন্ট সঠিকভাবে দেখানোর জন্য ন্যূনতম কত উচ্চতা প্রয়োজন?
  • Modifier.height(IntrinsicSize.Max) - আপনার কন্টেন্ট সঠিকভাবে দেখানোর জন্য সর্বাধিক কত উচ্চতা প্রয়োজন?

যেমন, আপনি যদি কাস্টম লে-আউটে অসীম width সীমাবদ্ধতা সহ Text-এর minIntrinsicHeight জিজ্ঞাসা করেন, তাহলে এটি একটি লাইনে আঁকা টেক্সট সহ Text-এর height ফিরিয়ে দেয়।

ইন্ট্রিনসিক্স ইন অ্যাকশন

আপনি এমন একটি কম্পোজেবল তৈরি করতে পারেন যা স্ক্রিনে দুটি টেক্সট দেখায়, যেগুলি একটি ডিভাইডার দিয়ে আলাদা করা থাকে:

দুটি টেক্সট এলিমেন্ট পাশাপাশি, তাদের মধ্যে একটি উল্লম্ব বিভাজক সহ

এটি করতে, দুটি Text কম্পোজেবল সহ একটি Row ব্যবহার করুন যা উপলভ্য জায়গা পূরণ করে এবং মাঝখানে একটি Divider থাকে। Divider-এর উচ্চতা সবচেয়ে লম্বা Text-এর সমান হতে হবে এবং এটি পাতলা (width = 1.dp) হতে হবে।

@Composable
fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) {
    Row(modifier = modifier) {
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(start = 4.dp)
                .wrapContentWidth(Alignment.Start),
            text = text1
        )
        VerticalDivider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),

            text = text2
        )
    }
}

Divider পুরো স্ক্রিন জুড়ে বড় হয়ে দেখায়, যা কাঙ্খিত আচরণ নয়:

দুটি টেক্সট এলিমেন্ট পাশাপাশি, তাদের মধ্যে একটি ডিভাইডার সহ, কিন্তু ডিভাইডারটি টেক্সটের নিচের অংশ পর্যন্ত প্রসারিত হয়

এটি ঘটে কারণ Row প্রতিটি চাইল্ডকে আলাদাভাবে পরিমাপ করে এবং Text-এর উচ্চতা Divider-কে সীমাবদ্ধ করতে ব্যবহার করা যাবে না।

পরিবর্তে, Divider যাতে নির্দিষ্ট উচ্চতা সহ উপলভ্য স্পেস পূরণ করে, তার জন্য height(IntrinsicSize.Min) মডিফায়ার ব্যবহার করুন।

height(IntrinsicSize.Min) তার চাইল্ডের সাইজ এমনভাবে নির্ধারণ করে যাতে সেটি তার ন্যূনতম ইন্ট্রিনসিক উচ্চতার সমান হয়। এই মডিফায়ারটি রিকার্সিভ হওয়ার কারণে, এটি Row এবং এর চাইল্ডের minIntrinsicHeight কোয়েরি করে।

আপনার কোডে এই মডিফায়ার প্রয়োগ করলে এটি প্রত্যাশা অনুযায়ী কাজ করে:

@Composable
fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) {
    Row(modifier = modifier.height(IntrinsicSize.Min)) {
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(start = 4.dp)
                .wrapContentWidth(Alignment.Start),
            text = text1
        )
        VerticalDivider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),

            text = text2
        )
    }
}

// @Preview
@Composable
fun TwoTextsPreview() {
    MaterialTheme {
        Surface {
            TwoTexts(text1 = "Hi", text2 = "there")
        }
    }
}

প্রিভিউ সহ:

দুটি টেক্সট এলিমেন্ট পাশাপাশি, তাদের মধ্যে একটি উল্লম্ব বিভাজক সহ

Row-এর উচ্চতা এইভাবে নির্ধারণ করা হয়:

  • Row কম্পোজেবলের minIntrinsicHeight হল এর চিলড্রেনের সর্বাধিক minIntrinsicHeight।
  • Divider এলিমেন্টের minIntrinsicHeight হল ০, কারণ কোনও সীমাবদ্ধতা না থাকলে এটি জায়গা দখল করে না।
  • Text minIntrinsicHeight হল নির্দিষ্ট width-এর জন্য টেক্সটের।
  • তাই, Row এলিমেন্টের height কনস্ট্রেন্ট Text-এর সর্বাধিক minIntrinsicHeight হয়ে যায়।
  • Divider তারপর Row-এর দেওয়া height সীমাবদ্ধতা অনুযায়ী তার height প্রসারিত করে।

আপনার কাস্টম লেআউটে ইন্ট্রিনসিক্স

কাস্টম Layout বা layout মডিফায়ার তৈরি করার সময়, আনুমানিক হিসেবের উপর ভিত্তি করে ইন্ট্রিনসিক পরিমাপ অটোমেটিক গণনা করা হয়। তাই, সব লেআউটের জন্য হিসাব সঠিক নাও হতে পারে। এইসব API-তে এইসব ডিফল্ট ওভাররাইড করার বিকল্প রয়েছে।

আপনার কাস্টম Layout-এর ইন্ট্রিনসিক পরিমাপ নির্দিষ্ট করতে, minIntrinsicWidth, minIntrinsicHeight, maxIntrinsicWidth এবং maxIntrinsicHeight ওভাররাইড করুন, MeasurePolicy ইন্টারফেস তৈরি করার সময়।

@Composable
fun MyCustomComposable(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        content = content,
        modifier = modifier,
        measurePolicy = object : MeasurePolicy {
            override fun MeasureScope.measure(
                measurables: List<Measurable>,
                constraints: Constraints
            ): MeasureResult {
                // Measure and layout here
                // ...
            }

            override fun IntrinsicMeasureScope.minIntrinsicWidth(
                measurables: List<IntrinsicMeasurable>,
                height: Int
            ): Int {
                // Logic here
                // ...
            }

            // Other intrinsics related methods have a default value,
            // you can override only the methods that you need.
        }
    )
}

আপনার কাস্টম layout মডিফায়ার তৈরি করার সময়, LayoutModifier ইন্টারফেসে সম্পর্কিত পদ্ধতি ওভাররাইড করুন।

fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier {

    override fun MeasureScope.measure(
        measurable: Measurable,
        constraints: Constraints
    ): MeasureResult {
        // Measure and layout here
        // ...
    }

    override fun IntrinsicMeasureScope.minIntrinsicWidth(
        measurable: IntrinsicMeasurable,
        height: Int
    ): Int {
        // Logic here
        // ...
    }

    // Other intrinsics related methods have a default value,
    // you can override only the methods that you need.
}