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

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

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

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

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

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

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

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

يمكنك استخدام المُعدِّل layout لتعديل طريقة قياس العنصر وعرضه . Layout هي lambda؛ وتشمل معاملاتها العنصر الذي يمكنك قياسه، تم تمريره كـ 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 استنادًا إلى اتجاه التنسيق (من اليسار إلى اليمين مقابل من اليمين إلى اليسار).

التنسيقات المخصصة قيد التشغيل

مزيد من المعلومات حول التنسيقات والمعدِّلات في التنسيقات الأساسية في Compose ومشاهدة التنسيقات المخصصة قيد التشغيل في إنشاء النماذج التي تنشئ تنسيقات مخصصة

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

لمعرفة المزيد من المعلومات عن التنسيقات المخصصة في Compose، راجِع الإرشادات الإضافية التالية الموارد.

الفيديوهات