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

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

تتيح لك سمات Intrinsics إرسال طلبات بحث عن الأطفال قبل قياس بياناتهم.

يمكنك طلب 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 صفرًا، لأنّه لا يشغل أي مساحة إذا لم يتم تحديد أي قيود.
  • 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.
}