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

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

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

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

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

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

يحدِّد استخدام النطاقات الحالات التي يمكنك فيها قياس أداء أطفالك ووضعهم له. لا يمكن قياس التخطيط إلا أثناء عمليات القياس وتمريرات التخطيط، ولا يمكن وضع عنصر ثانوي إلا أثناء تمريرات التخطيط (وبعد قياسه فقط). نظرًا لنطاقات Compose مثل MeasurementScope ومواضع الإعلانات، يتم فرض ذلك في وقت التجميع.

استخدام أداة تعديل التنسيق

يمكنك استخدام المعدِّل 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، يُرجى الرجوع إلى الموارد الإضافية التالية.

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