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

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

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

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

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

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

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

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

لمزيد من المعلومات حول التنسيقات المخصّصة في "الكتابة"، يُرجى الاطّلاع على المراجع الإضافية التالية.

الفيديوهات