ConstraintLayout ในการเขียน

ConstraintLayout เป็นเลย์เอาต์ที่ให้คุณวาง Composable เทียบกับ Composable อื่นๆ บนหน้าจอ เป็นอีกทางเลือกหนึ่งแทนที่จะใช้การซ้อนหลายระดับ Row, Column, Box และองค์ประกอบการออกแบบที่กำหนดเองอื่นๆ ConstraintLayout มีประโยชน์เมื่อใช้เลย์เอาต์ขนาดใหญ่ที่มีข้อกำหนดการจัดตำแหน่งที่ซับซ้อนมากขึ้น

พิจารณาใช้ ConstraintLayout ในสถานการณ์ต่อไปนี้

  • เพื่อหลีกเลี่ยงการฝัง Column และ Row หลายรายการเพื่อวางตำแหน่งองค์ประกอบบนหน้าจอเพื่อปรับปรุงความอ่านง่ายของโค้ด
  • เพื่อวางองค์ประกอบคอมโพสพอยต์ให้สัมพันธ์กับองค์ประกอบคอมโพสพอยต์อื่นๆ หรือวางองค์ประกอบคอมโพสพอยต์ตามเส้นกํากับ สิ่งกีดขวาง หรือเชน

ในระบบมุมมอง ConstraintLayout เป็นวิธีที่แนะนำในการสร้างเลย์เอาต์ขนาดใหญ่และซับซ้อน เนื่องจากลําดับชั้นมุมมองแบบแบนมีประสิทธิภาพดีกว่ามุมมองที่ฝัง แต่ข้อกังวลนี้ไม่มีใน Compose ซึ่งจัดการลําดับชั้นเลย์เอาต์แบบลําลึกได้อย่างมีประสิทธิภาพ

เริ่มต้นใช้งาน ConstraintLayout

หากต้องการใช้ ConstraintLayout ใน Compose คุณต้องเพิ่มทรัพยากร Dependency นี้ใน build.gradle (นอกเหนือจาก การตั้งค่าการเขียน)

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

ConstraintLayout ในเครื่องมือเขียนจะทํางานด้วยวิธีต่อไปนี้โดยใช้ DSL

  • สร้างการอ้างอิงสำหรับคอมโพสิเบิลแต่ละรายการใน ConstraintLayout โดยใช้ createRefs() หรือ createRefFor()
  • ระบุข้อจำกัดโดยใช้ตัวแก้ไข constrainAs() ซึ่งจะใช้การอ้างอิงเป็นพารามิเตอร์และให้คุณระบุข้อจำกัดของตัวแปรนั้นในบอดี้ของ Lambda
  • ระบุข้อจำกัดโดยใช้ linkTo() หรือวิธีการอื่นๆ ที่เป็นประโยชน์
  • parent คือข้อมูลอ้างอิงที่มีอยู่ซึ่งสามารถใช้เพื่อระบุข้อจำกัดสำหรับ Composable ConstraintLayout เอง

ต่อไปนี้คือตัวอย่างของ Composable ที่ใช้ 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 ระบุข้อจำกัดในบรรทัดโดยมีตัวปรับใน Composable ด้วย อย่างไรก็ตาม ก็มีบางกรณีที่ควรแยกข้อจำกัดออกจากเลย์เอาต์ที่ใช้ เช่น คุณอาจต้องการเปลี่ยนข้อจำกัดตามการกำหนดค่าหน้าจอ หรือสร้างภาพเคลื่อนไหวระหว่างชุดข้อจำกัด 2 ชุด

ในกรณีเช่นนี้ คุณสามารถใช้ 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 มีแนวคิดต่างๆ เช่น เส้นกํากับ สิ่งกีดขวาง และเชน ซึ่งช่วยในการวางองค์ประกอบภายใน Composable

หลักเกณฑ์

หลักเกณฑ์คือตัวช่วยเล็กๆ ที่มองเห็นได้ซึ่งใช้ออกแบบเลย์เอาต์ คอมโพสิเบิลสามารถถูกจำกัดตามหลักเกณฑ์ได้ เส้นกํากับมีประโยชน์ในการวางองค์ประกอบที่ dp หรือ percentage ที่เจาะจงภายในคอมโพสิชันหลัก

หลักเกณฑ์มี 2 ประเภท ได้แก่ แนวตั้งและแนวนอน สอง แนวนอนคือ top และ bottom และประเภทธุรกิจ 2 รายการคือ 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: การเว้นวรรคจะกระจายเท่าๆ กันใน Composable ทั้งหมด รวมถึงพื้นที่ว่างก่อน Composable แรกและหลัง Composable
  • ChainStyle.SpreadInside: พื้นที่ทำงานจะกระจายอย่างเท่าๆ กันสำหรับองค์ประกอบทั้งหมด Composable โดยไม่มีพื้นที่ว่างก่อน Composable แรกหรือหลังจาก Composable ล่าสุด
  • ChainStyle.Packed: พื้นที่ทำงานจะกระจายอยู่ก่อนรายการแรกและหลัง Composable ล่าสุดจะต่อกันโดยไม่มีช่องว่างระหว่าง ระหว่างกัน

ดูข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับ ConstraintLayout ใน Compose จาก API ที่ใช้งานจริงในตัวอย่างการเขียนที่ใช้ ConstraintLayout

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

อัปเดตแล้ว Apr 9, 2025

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

อัปเดตแล้ว Apr 9, 2025

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

อัปเดตแล้ว Apr 9, 2025