التنسيق المحدود في خانة إدخال المحتوى

ConstraintLayout هو تنسيق يسمح لك بوضع عارضات قابلة للإنشاء مقارنةً بالعناصر الأخرى القابلة للمشاركة على الشاشة. وهو بديل لاستخدام عدّة عناصر مدمجة: Row وColumn وBox وعناصر تنسيق مخصّصة أخرى. ويكون ConstraintLayout مفيدًا عند تنفيذ تنسيقات أكبر حجمًا مع متطلبات محاذاة أكثر تعقيدًا.

يمكنك استخدام ConstraintLayout في السيناريوهات التالية:

  • لتجنّب دمج عناصر Column وRow متعددة لتحديد موضع العناصر على الشاشة لتحسين سهولة قراءة الرمز.
  • لتحديد موضع التركيبات مقارنةً بالتركيبات الأخرى أو تحديد مواضعها بناءً على الإرشادات أو الحواجز أو السلاسل.

في نظام العرض، كان ConstraintLayout هو الطريقة المُقترَحة لإنشاء تنسيقات كبيرة ومعقدة، حيث كان الأداء التدرّجي الهرمي للعرض أفضل أفضل من الأداء في العروض المتداخلة. ومع ذلك، لا داعي للقلق بشأن ميزة "الإنشاء"، والتي يمكنها معالجة التسلسل الهرمي للتنسيق العميق.

بدء استخدام ConstraintLayout

لاستخدام ConstraintLayout في ميزة "إنشاء"، يجب إضافة هذه الاعتمادية في build.gradle (بالإضافة إلى إعداد الإنشاء):

implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"

يعمل ConstraintLayout في Compose بالطريقة التالية باستخدام DSL:

  • أنشِئ مراجع لكل عنصر قابل للإنشاء في ConstraintLayout باستخدام createRefs() أو createRefFor()
  • يتم توفير القيود باستخدام المُعدِّل constrainAs()، الذي يستخدِم المرجع كمَعلمة ويتيح لك تحديد قيوده في نص lambda.
  • يتم تحديد القيود باستخدام linkTo() أو طرق أخرى مفيدة.
  • parent هو مرجع حالي يمكن استخدامه لتحديد القيود المفروضة على ConstraintLayout القابلة للإنشاء.

في ما يلي مثال على مركّب باستخدام ConstraintLayout:

@Composable
fun ConstraintLayoutContent() {
    ConstraintLayout {
        // Create references for the composables to constrain
        val (button, text) = createRefs()

        Button(
            onClick = { /* Do something */ },
            // Assign reference "button" to the Button composable
            // and constrain it to the top of the ConstraintLayout
            modifier = Modifier.constrainAs(button) {
                top.linkTo(parent.top, margin = 16.dp)
            }
        ) {
            Text("Button")
        }

        // Assign reference "text" to the Text composable
        // and constrain it to the bottom of the Button composable
        Text(
            "Text",
            Modifier.constrainAs(text) {
                top.linkTo(button.bottom, margin = 16.dp)
            }
        )
    }
}

يقيّد هذا الرمز أعلى Button إلى العنصر الرئيسي بالهامش 16.dp وText في أسفل Button أيضًا مع هامش 16.dp.

تعرض زرًا وعنصرًا نصيًا مرتبَين في ConstraintLayout

واجهة برمجة تطبيقات منفصلة

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

في مثل هذه الحالات، يمكنك استخدام ConstraintLayout بطريقة مختلفة:

  1. أدخِل ConstraintSet كمَعلمة إلى ConstraintLayout.
  2. يمكنك تخصيص المراجع التي تم إنشاؤها في ConstraintSet للتركيبات باستخدام أداة تعديل layoutId.

@Composable
fun DecoupledConstraintLayout() {
    BoxWithConstraints {
        val constraints = if (minWidth < 600.dp) {
            decoupledConstraints(margin = 16.dp) // Portrait constraints
        } else {
            decoupledConstraints(margin = 32.dp) // Landscape constraints
        }

        ConstraintLayout(constraints) {
            Button(
                onClick = { /* Do something */ },
                modifier = Modifier.layoutId("button")
            ) {
                Text("Button")
            }

            Text("Text", Modifier.layoutId("text"))
        }
    }
}

private fun decoupledConstraints(margin: Dp): ConstraintSet {
    return ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        constrain(button) {
            top.linkTo(parent.top, margin = margin)
        }
        constrain(text) {
            top.linkTo(button.bottom, margin)
        }
    }
}

بعد ذلك، عندما تحتاج إلى تغيير القيود، يمكنك ضبط ConstraintSet مختلف.

المفاهيم الأساسية للقيود

يحتوي ConstraintLayout على مفاهيم مثل الإرشادات والعوائق والسلاسل التي يمكن أن تساعد في تحديد موضع العناصر داخل Composable.

الإرشادات

إنّ الإرشادات هي أدوات مساعدة مرئية صغيرة لتصميم التصميمات باستخدامها. يمكن حصر المحتوى القابل للإنشاء بإرشادات. تكون الإرشادات مفيدة لوضع العناصر على dp أو percentage معيّنة ضمن العنصر الرئيسي القابل للإنشاء.

هناك نوعان مختلفان من الإرشادات: عمودي وأفقي. والنوعان الأفقيان هما top وbottom، والعمودان هما start وend.

ConstraintLayout {
    // Create guideline from the start of the parent at 10% the width of the Composable
    val startGuideline = createGuidelineFromStart(0.1f)
    // Create guideline from the end of the parent at 10% the width of the Composable
    val endGuideline = createGuidelineFromEnd(0.1f)
    //  Create guideline from 16 dp from the top of the parent
    val topGuideline = createGuidelineFromTop(16.dp)
    //  Create guideline from 16 dp from the bottom of the parent
    val bottomGuideline = createGuidelineFromBottom(16.dp)
}

لإنشاء إرشادات، استخدِم createGuidelineFrom* مع نوع الإرشادات. يؤدي هذا الإجراء إلى إنشاء مرجع يمكن استخدامه في كتلة Modifier.constrainAs().

حواجز

تشير الحواجز إلى عدّة مواد قابلة للإنشاء لإنشاء إرشادات افتراضية استنادًا إلى الأداة القصوى في الجانب المعنيّ.

لإنشاء حاجز، استخدِم createTopBarrier() (أو: createBottomBarrier() و createEndBarrier() وcreateStartBarrier()) وقدِّم المراجع التي يجب أن تشكّل الحاجز.

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val topBarrier = createTopBarrier(button, text)
    }
}

ويمكن بعد ذلك استخدام الحاجز في كتلة Modifier.constrainAs().

السلاسل

توفر السلاسل سلوكًا يشبه المجموعات في محور واحد (أفقيًا أو عموديًا). يمكن تقييد المحاور الأخرى بشكل مستقل.

لإنشاء سلسلة، استخدِم createVerticalChain أو createHorizontalChain:

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val verticalChain = createVerticalChain(button, text, chainStyle = ChainStyle.Spread)
        val horizontalChain = createHorizontalChain(button, text)
    }
}

ويمكن بعد ذلك استخدام السلسلة في مجموعة Modifier.constrainAs().

يمكن ضبط سلسلة باستخدام ChainStyles مختلفة، ما يحدِّد كيفية التعامل مع المساحة المحيطة بتركيبة مثل:

  • ChainStyle.Spread: يتم توزيع المساحة بالتساوي على جميع المكونات القابلة للتركيب، بما في ذلك المساحة الخالية قبل أول تركيب وبعد التركيبة الأخيرة.
  • ChainStyle.SpreadInside: يتم توزيع المساحة بالتساوي على جميع العناصر القابلة للإنشاء، بدون أي مساحة فارغة قبل أوّل تركيب.
  • ChainStyle.Packed: يتم توزيع المسافات قبل الأول والثاني الذي يمكن تجميعه معًا، ويتم تجميعها معًا بدون مسافة بين بعضها البعض.

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

اطّلِع على مزيد من المعلومات عن آلية ConstraintLayout في الإنشاء من واجهات برمجة التطبيقات في إنشاء نماذج تستخدم ConstraintLayout.