ConstraintLayout چیدمانی است که به شما امکان میدهد composableها را نسبت به
composableهای دیگر در صفحه قرار دهید. این روش جایگزینی برای استفاده از چندین
Row، Column، Box، و عنصر چیدمان سفارشی تودرتو است.
در سیستم View، ConstraintLayout روش توصیهشده برای ایجاد چیدمانهای بزرگ و پیچیده بود، زیرا سلسلهمراتب نمای مسطح برای عملکرد بهتر از نماهای تودرتو بود. اما این موضوع در Compose نگرانکننده نیست، زیرا Compose میتواند بهطور مؤثری سلسلهمراتب چیدمان عمیق را مدیریت کند، بنابراین ConstraintLayout چندان مفید نیست.
با ConstraintLayout شروع کنید
برای استفاده از ConstraintLayout در Compose، باید این وابستگی را در
build.gradle (علاوهبر راهاندازی Compose) اضافه کنید:
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
ConstraintLayout در Compose بااستفاده از
DSL به روش زیر کار میکند:
- برای هر composable در
ConstraintLayoutبااستفاده ازcreateRefs()یاcreateRefFor()مرجع ایجاد کنید. - محدودیتها بااستفاده از اصلاحکننده
constrainAs()ارائه میشوند که مرجع را بهعنوان پارامتر میگیرد و به شما امکان میدهد محدودیتهای آن را در بدنه لامبدا مشخص کنید. - محدودیتها بااستفاده از
linkTo()یا روشهای مفید دیگر مشخص میشوند. -
parentمرجع موجودی است که میتوان از آن برای مشخص کردن محدودیتها در خودConstraintLayoutcomposable استفاده کرد.
در اینجا مثالی از یک ترکیبپذیر بااستفاده از 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 به یکدیگر محدود شدهاند.
Decoupled API
در مثال ConstraintLayout، محدودیتها بهصورت درونخطی با یک
اصلاحکننده در ترکیبپذیری که به آن اعمال میشوند، مشخص شدهاند. بااینحال، شرایطی وجود دارد
که ترجیح داده میشود محدودیتها از طرحبندیهایی که بر آنها اعمال میشوند جدا شوند.
برای مثال، ممکن است بخواهید محدودیتها را براساس پیکربندی صفحه تغییر دهید، یا بین دو مجموعه محدودیت پویانمایی کنید.
برای مواردی مثل این، میتوانید از ConstraintLayout به روش دیگری استفاده کنید:
ConstraintSetرا بهعنوان پارامتر بهConstraintLayoutارسال کنید.- بااستفاده از اصلاحکننده
layoutId، مرجعهای ایجادشده درConstraintSetرا به composableها اختصاص دهید.
@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 حاوی مفاهیمی مانند خطوط راهنما، موانع، و زنجیرهها است
که میتواند به موقعیتیابی عناصر در داخل 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 مختلف پیکربندی کرد که تعیین میکند چگونه
با فضای اطراف یک composable برخورد شود، مانند:
ChainStyle.Spread: فضا بهطور مساوی در سراسر همه composableها توزیع میشود، ازجمله فضای آزاد قبلاز اولین composable و بعداز آخرین composable.ChainStyle.SpreadInside: فضا بهطور مساوی بین همه ترکیبپذیرها توزیع میشود، بدون اینکه فضای خالی قبلاز اولین ترکیبپذیر یا بعداز آخرین ترکیبپذیر وجود داشته باشد.ChainStyle.Packed: فضا قبلاز اولین و بعداز آخرین ترکیبپذیر توزیع میشود، ترکیبپذیرها بدون فاصله بین یکدیگر در کنار هم قرار میگیرند.