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

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

تسمح لك السمات الأساسية باستعلام الأطفال قبل قياسهم فعليًا.

يمكنك طلب intrinsicWidth أو intrinsicHeight للعنصر القابل للتجميع:

  • (min|max)IntrinsicWidth: استنادًا إلى هذا العرض، ما هو الحد الأدنى/الحد الأقصى للعرض الذي يمكنك من خلاله رسم المحتوى بشكل صحيح؟
  • (min|max)IntrinsicHeight: استنادًا إلى هذا الارتفاع، ما هو الحد الأدنى/الحد الأقصى للارتفاع الذي يمكنك من خلاله رسم المحتوى بشكل صحيح؟

على سبيل المثال، إذا طلبت minIntrinsicHeight من Text مع height لانهائي، سيعرض ال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
        )
        HorizontalDivider(
            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
        )
        HorizontalDivider(
            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")
        }
    }
}

عند استخدام ميزة المعاينة:

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

سيكون 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.
}