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

في أداة "الإنشاء"، يتم تمثيل عناصر واجهة المستخدم بواسطة الدوالّ القابلة للتجميع التي تُنشئ قطعة من واجهة المستخدم عند استدعائها، ثم تتم إضافتها إلى شجرة واجهة المستخدم التي يتم عرضها على الشاشة. يحتوي كل عنصر واجهة مستخدم على عنصر رئيسي واحد وربما العديد من العناصر الثانوية. يتم أيضًا وضع كل عنصر داخل العنصر الرئيسي، ويتم تحديده كموضع (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) ، والتي تقدّم أيضًا دالة lambda المستخدَمة لوضع العناصر المُغلفة. في هذه الحالة، يكون الارتفاع بين القاعدة الأخيرة والمساحة المتروكة العلوية المُضافة.
  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 استنادًا إلى اتجاه التنسيق (من اليسار إلى اليمين مقابل من اليمين إلى اليسار).

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

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

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

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

الفيديوهات