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

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

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