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

في 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. في مَعلمة lambda measurable، يمكنك قياس 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، راجِع الموارد الإضافية التالية.

الفيديوهات الطويلة