من قواعد 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، لأنّه لا يشغل مساحة في حال عدم توفّر قيود. -
TextminIntrinsicHeightهو النص الخاص بـwidthمعيّن. - وبالتالي، يصبح قيد
heightللعنصرRowهو الحد الأقصىminIntrinsicHeightلـText. - بعد ذلك، يوسّع
Dividerheightإلى قيدheightالذي يوفّرهRow.
القياسات الجوهرية في التنسيقات المخصّصة
عند إنشاء مُعدِّل Layout أو layout مخصّص، يتم احتساب القياسات الجوهرية
تلقائيًا استنادًا إلى القيم التقريبية. لذلك، قد لا تكون الحسابات صحيحة لجميع التخطيطات. وتوفّر واجهات برمجة التطبيقات هذه خيارات
لتجاوز هذه الإعدادات التلقائية.
لتحديد قياسات الخصائص الجوهرية لـ Layout المخصّص، يمكنك إلغاء
minIntrinsicWidth وminIntrinsicHeight وmaxIntrinsicWidth وmaxIntrinsicHeight لواجهة MeasurePolicy عند إنشائها.
يجب أن يتطابق التجاوز مع ما يفعله measure. على سبيل المثال، في عمود مخصّص يكدّس عناصره الفرعية عموديًا ويمنح كل عنصر فرعي عرض العمود بالكامل، يكون الحد الأدنى للارتفاع الجوهري لعنصر width معيّن هو مجموع الحد الأدنى للارتفاعات الجوهرية لعناصره الفرعية لعنصر width هذا:
@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 { val childConstraints = constraints.copy(minHeight = 0) val placeables = measurables.map { measurable -> measurable.measure(childConstraints) } val width = constraints.constrainWidth( placeables.maxOfOrNull { it.width } ?: 0 ) val height = constraints.constrainHeight( placeables.sumOf { it.height } ) return layout(width, height) { var yPosition = 0 placeables.forEach { placeable -> placeable.placeRelative(x = 0, y = yPosition) yPosition += placeable.height } } } override fun IntrinsicMeasureScope.minIntrinsicHeight( measurables: List<IntrinsicMeasurable>, width: Int ): Int { return measurables.sumOf { measurable -> measurable.minIntrinsicHeight(width) } } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
عند إنشاء معدِّل layout مخصّص، يمكنك إلغاء الطرق ذات الصلة
في واجهة LayoutModifier. يجب أن تتطابق عملية الحساب الجوهرية مع
measure. على سبيل المثال، بالنسبة إلى height معيّن، فإنّ المُعدِّل الذي يضيف مساحة متروكة ثابتة
على جميع الجوانب يطرح المساحة المتروكة العمودية قبل طلب minIntrinsicWidth للعنصر الثانوي، ويضيف المساحة المتروكة الأفقية إلى النتيجة:
fun Modifier.myCustomModifier(padding: Dp = 8.dp) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { val paddingPx = padding.roundToPx() val horizontal = paddingPx * 2 val vertical = paddingPx * 2 val placeable = measurable.measure( constraints.offset(-horizontal, -vertical) ) val width = constraints.constrainWidth(placeable.width + horizontal) val height = constraints.constrainHeight(placeable.height + vertical) return layout(width, height) { placeable.place(paddingPx, paddingPx) } } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { val paddingPx = padding.roundToPx() val horizontal = paddingPx * 2 val vertical = paddingPx * 2 val childHeight = if (height == Constraints.Infinity) { Constraints.Infinity } else { (height - vertical).coerceAtLeast(0) } return measurable.minIntrinsicWidth(childHeight) + horizontal } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
التطبيقات المقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما يكون JavaScript غير مفعَّل
- التنسيقات المخصّصة {:#custom-layouts}
- خطوط المحاذاة في Jetpack Compose
- مراحل Jetpack Compose