אילוץ פריסה בכתיבה

ConstraintLayout היא פריסה שמאפשרת להציב תכנים קומפוזביליים ביחס של תכנים קומפוזביליים אחרים במסך. היא חלופה לשימוש במספר Row, Column, Box ורכיבי פריסה אחרים בהתאמה אישית. ConstraintLayout שימושי כאשר מטמיעים פריסות גדולות יותר עם יישור מורכב יותר בדרישות שלנו.

מומלץ להשתמש ב-ConstraintLayout בתרחישים הבאים:

  • כדי להימנע מהצבת כמה אלמנטים מסוג Column ו-Row לצורך מיקום רכיבים כדי לשפר את קריאות הקוד.
  • למיקום של תכנים קומפוזביליים ביחס לתכנים קומפוזביליים אחרים או למיקום תכנים קומפוזביליים שמבוססים על הנחיות, מחסומים או רשתות.

במערכת View, הדרך המומלצת ליצירת תמונות היא ConstraintLayout ופריסות מורכבות, כי היררכיית תצוגה שטוחה הייתה טובה יותר לביצועים הן תצוגות מקוננות. עם זאת, אין בעיה כזו באפליקציית 'כתיבה', שיכולה לטפל ביעילות בהיררכיות של פריסה עמוקה.

התחל לעבוד עם ConstraintLayout

כדי להשתמש ב-ConstraintLayout בניסוח האוטומטי, צריך להוסיף את התלות הזו build.gradle (בנוסף ל- הגדרת פיתוח נייטיב):

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

ConstraintLayout בכתיבה פועל באופן הבא באמצעות 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

API לאחר ביטול צימוד

בדוגמה 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 מושגים

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: המרחב מחולק לפני הספרה הראשונה ואחריה התכנים הקומפוזביליים האחרונים נדחים יחד ללא רווח ביניהם שתי רשתות נוירונים זו מול זו.

מידע נוסף

מידע נוסף על ConstraintLayout ב-Composer מממשקי ה-API בפעולה כתיבת דוגמאות שמשתמשות ב-ConstraintLayout.