التنسيقات المخصصة

في أداة "الإنشاء"، يتم تمثيل عناصر واجهة المستخدم بواسطة الدوالّ القابلة للتجميع التي تُنشئ قطعة من واجهة المستخدم عند استدعائها، ثم تتم إضافتها إلى شجرة واجهة المستخدم التي يتم عرضها على الشاشة. يحتوي كل عنصر واجهة مستخدم على عنصر رئيسي واحد وربما العديد من العناصر الثانوية. يتم أيضًا وضع كل عنصر داخل العنصر الرئيسي، ويتم تحديده كموضع (x, y) ومقاس، ويتم تحديده على أنّه width وheight.

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

تتطلّب عملية وضع كل عقدة في شجرة واجهة المستخدم ثلاث خطوات. يجب أن تستوفي كل عقدة ما يلي:

  1. قياس أيّ عناصر ثانوية
  2. تحديد حجمها الخاص
  3. وضع العناصر الثانوية

ثلاث خطوات لتصميم العقدة: قياس العناصر الفرعية، وتحديد الحجم، ووضع العناصر الفرعية

يحدِّد استخدام النطاقات الوقت الذي يمكنك فيه قياس أداء أطفالك وتحديد أماكنهم. لا يمكن قياس تنسيق إلا أثناء عمليات القياس وتنسيق الإعلانات، ولا يمكن وضع عنصر فرعي إلا أثناء عمليات تنسيق الإعلانات (وبعد قياسه فقط). يتم فرض ذلك في وقت الترجمة بسبب نطاقات Compose، مثل MeasureScope، وPlacementScope.

استخدام مُعدِّل التنسيق

يمكنك استخدام المُعدِّل layout لتعديل طريقة قياس العنصر وعرضه. Layout هي دالة لامبدا، وتشمل مَعلماتها العنصر الذي يمكنك قياسه، ويُمرَّر على النحو التالي:measurable، والقيود الواردة في العنصر القابل للتجميع، ويُمرَّر على النحو التالي:constraints. يمكن أن يبدو مُعدِّل التنسيق المخصّص على النحو التالي:

fun Modifier.customLayoutModifier() =
    layout { measurable, constraints ->
        // ...
    }

لنعرِض Text على الشاشة ونتحكّم في المسافة من الأعلى إلى قاعدة السطر الأول من النص. هذا هو بالضبط ما يفعله المُعدِّل paddingFromBaseline، وسنطبّقه هنا كمثال. لإجراء ذلك، استخدِم المُعدِّل layout لوضع العنصر القابل للتجميع يدويًا على الشاشة. في ما يلي السلوك المطلوب عند ضبط Text الحشو العلوي 24.dp:

يعرض الفرق بين المساحة المتروكة العادية لواجهة المستخدم، التي تحدد المسافة بين العناصر، والمساحة المتروكة للنص التي تحدد المسافة من خط أساس إلى آخر.

إليك الرمز لإنتاج هذا التباعد:

fun Modifier.firstBaselineToTop(
    firstBaselineToTop: Dp
) = layout { measurable, constraints ->
    // Measure the composable
    val placeable = measurable.measure(constraints)

    // Check the composable has a first baseline
    check(placeable[FirstBaseline] != AlignmentLine.Unspecified)
    val firstBaseline = placeable[FirstBaseline]

    // Height of the composable with padding - first baseline
    val placeableY = firstBaselineToTop.roundToPx() - firstBaseline
    val height = placeable.height + placeableY
    layout(placeable.width, height) {
        // Where the composable gets placed
        placeable.placeRelative(0, placeableY)
    }
}

في ما يلي ما يحدث في هذا الرمز البرمجي:

  1. في مَعلمة measurable lambda، يمكنك قياس Text الذي يمثّله المَعلمة القابلة للقياس من خلال استدعاء measurable.measure(constraints).
  2. يمكنك تحديد حجم المحتوى القابل للإنشاء من خلال استدعاء الطريقة layout(width, height) ، والتي تقدّم أيضًا دالة لامبادا المستخدَمة لوضع العناصر المُغلفة. في هذه الحالة، يكون الارتفاع بين القاعدة الأخيرة والمساحة المتروكة العلوية المُضافة.
  3. يمكنك تحديد موضع العناصر المُلفَّفة على الشاشة من خلال استدعاء placeable.place(x, y). إذا لم يتم وضع العناصر المُغلفة، لن تكون مرئية. يتطابق موضع y مع الحشو العلوي، وهو موضع أول خط أساس للنص.

للتأكّد من أنّ هذا يعمل على النحو المتوقّع، استخدِم هذا المُعدِّل في Text:

@Preview
@Composable
fun TextWithPaddingToBaselinePreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.firstBaselineToTop(32.dp))
    }
}

@Preview
@Composable
fun TextWithNormalPaddingPreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.padding(top = 32.dp))
    }
}

معاينات متعددة لعناصر النص: يعرض أحدها مساحة بادئة عادية بين العناصر، ويعرض الآخر مساحة بادئة من خط أساس إلى آخر

إنشاء تنسيقات مخصّصة

لا يغيّر المُعدِّل layout سوى العنصر القابل للتجميع للمكالمة. لقياس وتنسيق عناصر قابلة للتجميع متعددة، استخدِم العنصر القابل للتجميع Layout بدلاً من ذلك. تتيح لك هذه الميزة القابلة للتجميع قياس العناصر الفرعية وعرضها يدويًا. تم إنشاء جميع التنسيقات ذات المستوى الأعلى مثل Column وRow باستخدام العنصر القابل للتجميع Layout.

لننشئ نسخة أساسية جدًا من Column. تتّبع معظم التنسيقات المخصّصة هذا النمط:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // measure and position children given constraints logic here
        // ...
    }
}

على غرار المُعدِّل layout، measurables هي قائمة العناصر الفرعية التي يجب قياسها وconstraints هي القيود من العنصر الرئيسي. باتّباع المنطق نفسه كما في السابق، يمكن تنفيذ MyBasicColumn على النحو التالي:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // Don't constrain child views further, measure them with given constraints
        // List of measured children
        val placeables = measurables.map { measurable ->
            // Measure each children
            measurable.measure(constraints)
        }

        // Set the size of the layout as big as it can
        layout(constraints.maxWidth, constraints.maxHeight) {
            // Track the y co-ord we have placed children up to
            var yPosition = 0

            // Place children in the parent layout
            placeables.forEach { placeable ->
                // Position item on the screen
                placeable.placeRelative(x = 0, y = yPosition)

                // Record the y co-ord placed up to
                yPosition += placeable.height
            }
        }
    }
}

تخضع العناصر المركّبة الفرعية لقيود Layout (بدون قيود minHeight)، ويتم وضعها استنادًا إلى yPosition للعنصر المركّب السابق.

في ما يلي كيفية استخدام هذا العنصر المخصّص القابل للتجميع:

@Composable
fun CallingComposable(modifier: Modifier = Modifier) {
    MyBasicColumn(modifier.padding(8.dp)) {
        Text("MyBasicColumn")
        Text("places items")
        Text("vertically.")
        Text("We've done it by hand!")
    }
}

عدة عناصر نصية فوق بعضها في عمود

اتجاه التنسيق

يمكنك تغيير اتجاه تنسيق عنصر قابل للتجميع من خلال تغيير ملف تكوين LocalLayoutDirection المحلي.

إذا كنت تضع عناصر قابلة للإنشاء يدويًا على الشاشة، سيكون LayoutDirection جزءًا من LayoutScope في مفتاح التعديل layout أو عنصر Layout القابل للإنشاء.

عند استخدام layoutDirection، ضَع عناصر قابلة للإنشاء باستخدام place. على عكس placeRelative ، لا يتغيّر الرمز place استنادًا إلى اتجاه التنسيق (من اليسار إلى اليمين أو من اليمين إلى اليسار).

التنسيقات المخصّصة في العمل

تعرّف على مزيد من المعلومات حول التنسيقات والمفاتيح في التنسيقات الأساسية في Compose، والاطّلاع على التنسيقات المخصّصة عمليًا في نماذج الإنشاء التي تنشئ تنسيقات مخصّصة.

مزيد من المعلومات

لمزيد من المعلومات عن التنسيقات المخصّصة في ميزة "الإنشاء"، يمكنك الرجوع إلى المراجع التالية.

الفيديوهات