กฎข้อหนึ่งของ Compose คือคุณควรวัดองค์ประกอบย่อยเพียงครั้งเดียว การวัดองค์ประกอบย่อย 2 ครั้งจะทำให้เกิดข้อยกเว้นรันไทม์ อย่างไรก็ตาม มีบางครั้งที่คุณต้องการข้อมูลบางอย่างเกี่ยวกับองค์ประกอบย่อยก่อนที่จะวัด
Intrinsics ช่วยให้คุณค้นหาองค์ประกอบย่อยก่อนที่จะวัดจริงได้
คุณสามารถขอ IntrinsicSize.Min หรือ IntrinsicSize.Max ของ Composable ได้ดังนี้
Modifier.width(IntrinsicSize.Min)- ความกว้างขั้นต่ำที่จำเป็นในการแสดงเนื้อหาอย่างเหมาะสมคือเท่าใดModifier.width(IntrinsicSize.Max)- ความกว้างสูงสุดที่จำเป็นในการแสดงเนื้อหาอย่างเหมาะสมคือเท่าใดModifier.height(IntrinsicSize.Min)- ความสูงขั้นต่ำที่จำเป็นในการแสดงเนื้อหาอย่างเหมาะสมคือเท่าใดModifier.height(IntrinsicSize.Max)- ความสูงสูงสุดที่คุณต้องการเพื่อแสดงเนื้อหาอย่างเหมาะสมคือเท่าใด
ตัวอย่างเช่น หากคุณขอ minIntrinsicHeight ของ Text ที่มีข้อจำกัด width แบบไม่จำกัดในเลย์เอาต์ที่กำหนดเอง ระบบจะแสดงผล height ของ Text โดยมีข้อความที่วาดในบรรทัดเดียว
การทำงานของ Intrinsics
คุณสามารถสร้าง Composable ที่แสดงข้อความ 2 รายการบนหน้าจอโดยคั่นด้วยตัวแบ่งได้ดังนี้
โดยใช้ Row กับ Composable Text 2 รายการที่เติมพื้นที่ว่าง และ Divider ตรงกลาง Divider ควรมีความสูงเท่ากับ Text ที่สูงที่สุด และควรมีความบาง (width = 1.dp)
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
Divider ขยายเต็มหน้าจอ ซึ่งไม่ใช่ลักษณะการทำงานที่ต้องการ
ซึ่งเป็นเพราะ Row วัดองค์ประกอบย่อยแต่ละรายการแยกกัน และความสูงของ Text ไม่สามารถใช้เพื่อจำกัด Divider ได้
หากต้องการให้ Divider เติมพื้นที่ว่างที่มีอยู่ด้วยความสูงที่กำหนดแทน ให้ใช้ตัวปรับแต่ง height(IntrinsicSize.Min)
height(IntrinsicSize.Min) ปรับขนาดองค์ประกอบย่อยให้สูงเท่ากับความสูงภายในขั้นต่ำ เนื่องจากตัวแก้ไขนี้เป็นแบบเรียกซ้ำ จึงจะค้นหา minIntrinsicHeight ของ Row และรายการย่อย
การใช้ตัวแก้ไขนี้กับโค้ดจะทำให้โค้ดทำงานได้ตามที่คาดไว้
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier.height(IntrinsicSize.Min)) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } } // @Preview @Composable fun TwoTextsPreview() { MaterialTheme { Surface { TwoTexts(text1 = "Hi", text2 = "there") } } }
เมื่อมีตัวอย่าง
ความสูงของ Row จะกำหนดดังนี้
minIntrinsicHeightของRowComposable คือminIntrinsicHeightสูงสุดขององค์ประกอบย่อยminIntrinsicHeightขององค์ประกอบDividerคือ 0 เนื่องจากจะไม่ใช้พื้นที่หากไม่มีข้อจำกัดTextminIntrinsicHeightคือภาษาของข้อความสำหรับwidthที่เฉพาะเจาะจง- ดังนั้น ข้อจำกัด
heightขององค์ประกอบRowจึงกลายเป็นค่าสูงสุดminIntrinsicHeightของText - จากนั้น
Dividerจะขยายheightไปยังข้อจำกัดheightที่กำหนดโดยRow
องค์ประกอบภายในในเลย์เอาต์ที่กำหนดเอง
เมื่อสร้างตัวแก้ไข Layout หรือ layout ที่กำหนดเอง ระบบจะคำนวณการวัดค่าภายในโดยอัตโนมัติตามค่าประมาณ ดังนั้นการคำนวณจึงอาจไม่ถูกต้องสำหรับเลย์เอาต์บางแบบ API เหล่านี้มีตัวเลือกในการลบล้างค่าเริ่มต้นเหล่านี้
หากต้องการระบุการวัดค่าภายในของ Layout ที่กำหนดเอง ให้ลบล้าง minIntrinsicWidth, minIntrinsicHeight, maxIntrinsicWidth และ maxIntrinsicHeight ของอินเทอร์เฟซ MeasurePolicy เมื่อสร้าง
@Composable fun MyCustomComposable( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( content = content, modifier = modifier, measurePolicy = object : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurables: List<IntrinsicMeasurable>, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
เมื่อสร้างตัวแก้ไข layout ที่กำหนดเอง ให้ลบล้างเมธอดที่เกี่ยวข้องในอินเทอร์เฟซ LayoutModifier
fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- เลย์เอาต์ที่กำหนดเอง {:#custom-layouts}
- เส้นการจัดแนวใน Jetpack Compose
- ระยะเวลาดำเนินการของ Jetpack Compose