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

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

বাচ্চাদের প্রকৃত পরিমাপ নেওয়ার আগেই ইন্ট্রিনসিক্স আপনাকে তাদের সম্পর্কে কোয়েরি করতে দেয়।

কোনও কম্পোজ করার মতো আইটেমের IntrinsicSize.Min বা IntrinsicSize.Max সম্পর্কে আপনি জানতে চাইতে পারেন:

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

যেমন, কাস্টম লেআউটে আপনি যদি Text-এর minIntrinsicHeight-এর জন্য অসীম width সীমাবদ্ধতার কথা বলেন, তাহলে এটি 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 তারপরে height-এর height-কে Row-এর দেওয়া সীমাবদ্ধতা পর্যন্ত প্রসারিত করে।

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

কাস্টম 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.
}