القياسات الأساسية في تنسيقات Compose

من قواعد Compose أنّه يجب قياس العناصر الثانوية مرة واحدة فقط، لأنّ قياسها مرتين يؤدي إلى ظهور استثناء في وقت التشغيل. ومع ذلك، هناك أوقات تحتاج فيها إلى بعض المعلومات عن أطفالك قبل قياسها.

تتيح لك ميزة "القياسات الجوهرية" الاستعلام عن العناصر الثانوية قبل قياسها فعليًا.

بالنسبة إلى دالة مركّبة، يمكنك طلب IntrinsicSize.Min أو IntrinsicSize.Max:

  • Modifier.width(IntrinsicSize.Min) - ما هو الحد الأدنى للعرض الذي تحتاجه لعرض المحتوى الخاص بك بشكل صحيح؟
  • Modifier.width(IntrinsicSize.Max) - ما هو الحد الأقصى للعرض الذي تحتاجه لعرض المحتوى الخاص بك بشكل صحيح؟
  • Modifier.height(IntrinsicSize.Min) - ما هو الحد الأدنى للارتفاع المطلوب لعرض المحتوى بشكل صحيح؟
  • Modifier.height(IntrinsicSize.Max) - ما هو الحد الأقصى للارتفاع المطلوب لعرض المحتوى بشكل صحيح؟

على سبيل المثال، إذا طلبت minIntrinsicHeight من Text مع قيود width لا نهائية في تنسيق مخصّص، سيتم عرض height من Text مع النص المرسوم في سطر واحد.

أمثلة على استخدام "السمات الجوهرية"

يمكنك إنشاء دالة مركّبة تعرض نصَّين على الشاشة يفصل بينهما فاصل:

عنصرا نص جنبًا إلى جنب، مع فاصل عمودي بينهما

لإجراء ذلك، استخدِم دالة Row مع دالتَين مركّبتَين من النوع Text تملآن المساحة المتاحة، ودالة 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) حجم العناصر الفرعية ليكون ارتفاعها مساويًا للحد الأدنى لارتفاعها الجوهري. بما أنّ هذا المُعدِّل متكرّر، فإنّه يطلب minIntrinsicHeight من Row وعناصره الفرعية.

يؤدي تطبيق هذا المُعدِّل على الرمز البرمجي إلى عمله على النحو المتوقّع:

@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 على النحو التالي:

  • تكون السمة minIntrinsicHeight للدالة المركّبة Row هي الحد الأقصى للسمة minIntrinsicHeight في العناصر الثانوية.
  • قيمة السمة minIntrinsicHeight للعنصر Divider هي 0، لأنّه لا يشغل مساحة في حال عدم توفّر قيود.
  • ‫Text minIntrinsicHeight هو النص الخاص بـ width معيّن.
  • وبالتالي، يصبح قيد height للعنصر Row هو الحد الأقصى لـ minIntrinsicHeight من Text.
  • بعد ذلك، يوسّع Divider height إلى قيد height الذي يوفّره Row.

القيم الجوهرية في التنسيقات المخصّصة

عند إنشاء مُعدِّل Layout أو layout مخصّص، يتم احتساب القياسات الجوهرية تلقائيًا استنادًا إلى القيم التقريبية. لذلك، قد لا تكون الحسابات صحيحة لجميع التخطيطات. وتوفّر واجهات برمجة التطبيقات هذه خيارات لتجاوز هذه الإعدادات التلقائية.

لتحديد قياسات الخصائص الجوهرية لـ 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.
}