القياسات الأساسية في تنسيقات 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‏ 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.
}