القياسات الأساسية في تنسيقات الإنشاء

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

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

إلى مركّب، يمكنك طلب توفّر intrinsicWidth أو intrinsicHeight:

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

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

العملية العملية

لنفترض أنّنا نريد إنشاء قابل للإنشاء يعرض نصَين على الشاشة مفصولة بفاصلة مثل هذا:

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

كيف يمكننا تنفيذ ذلك؟ يمكن أن نمتلئ Row بـ Text، ثم يوسع النطاق بأكبر قدر ممكن، ونضيف 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
        )
        Divider(
            color = Color.Black,
            modifier = Modifier.fillMaxHeight().width(1.dp)
        )
        Text(
            modifier = Modifier
                .weight(1f)
                .padding(end = 4.dp)
                .wrapContentWidth(Alignment.End),

            text = text2
        )
    }
}

إذا معاينةنا هذا، نرى أن الفاصل يتوسّع إلى الشاشة بأكملها، وهذا ليس ما نريده:

عنصران نصيان جنبًا إلى جنب، مع وضع فاصل بينهما، إلا أن الفاصل يمتد أسفل الجزء السفلي من النص

ويعود السبب في ذلك إلى أنّ 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
        )
        Divider(
            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 القابل للإنشاء minIntrinsicHeight هو الحد الأقصى من أطفاله الثانويين.Row وتكون قيمة العنصر Divider للعنصر minIntrinsicHeight هي 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.
}