ConstraintLayout هو تنسيق يتيح لك وضع العناصر القابلة للإنشاء بالنسبة إلى عناصر أخرى على الشاشة. وهو بديل لاستخدام عناصر متعدّدة من التنسيقات المتداخلة
Row وColumn وBox وعناصر التنسيق المخصّصة الأخرى.
في نظام العرض، كان ConstraintLayout هو الطريقة المقترَحة لإنشاء تنسيقات كبيرة ومعقّدة، لأنّ هيكلية طرق العرض المسطّحة كانت أفضل من حيث الأداء من العروض المتداخلة. ومع ذلك، لا يمثّل هذا مشكلة في Compose، الذي يمكنه التعامل بكفاءة مع تسلسلات التنسيق العميقة، لذا فإنّ `ConstraintLayout` ليس مفيدًا بالقدر نفسه.
بدء استخدام ConstraintLayout
لاستخدام ConstraintLayout في Compose، عليك إضافة هذا التبعية في ملف
build.gradle (بالإضافة إلى إعداد Compose):
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
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.
Button وText مقيّدان ببعضهما البعض في
ConstraintLayout.
واجهة برمجة التطبيقات غير المرتبطة
في مثال ConstraintLayout، يتم تحديد القيود مضمّنةً، باستخدام معدِّل في العنصر القابل للإنشاء الذي يتم تطبيقها عليه. ومع ذلك، هناك حالات يُفضّل فيها فصل القيود عن التنسيقات التي يتم تطبيقها عليها.
على سبيل المثال، قد تريد تغيير القيود استنادًا إلى إعدادات الشاشة، أو تحريكها بين مجموعتَي قيود.
في حالات مثل هذه، يمكنك استخدام ConstraintLayout بطريقة مختلفة:
- يمكنك تمرير
ConstraintSetكمعلَمة إلىConstraintLayout. - يمكنك تعيين المراجع التي تم إنشاؤها في الـ
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
يحتوي ConstraintLayout على مفاهيم مثل الإرشادات والحواجز والسلاسل التي يمكن أن تساعد في تحديد موضع العناصر داخل العنصر القابل للإنشاء.
الإرشادات
الإرشادات هي أدوات مرئية صغيرة تساعد في تصميم التنسيقات. يمكن تقييد العناصر القابلة للإنشاء بإرشاد. تكون الإرشادات مفيدة لوضع العناصر عند قيمة معيّنة 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: يتم توزيع المساحة قبل العنصر الأول وبعد العنصر الأخير، ويتم تجميع العناصر القابلة للإنشاء معًا بدون مساحة بينها.