กฎข้อหนึ่งของ 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
ที่มี 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)
จะกำหนดให้องค์ประกอบย่อยมีความสูงเท่ากับความสูงโดยธรรมชาติขั้นต่ำ เนื่องจากเป็นแบบเรียกซ้ำ ระบบจะค้นหา Row
และminIntrinsicHeight
เมื่อนำไปใช้กับโค้ดของเรา โค้ดจะทำงานตามที่คาดไว้
@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
Composable minIntrinsicHeight
จะมีค่าสูงสุด minIntrinsicHeight
ขององค์ประกอบย่อย Divider
ขององค์ประกอบ minIntrinsicHeight
คือ 0 เนื่องจากไม่ได้ใช้พื้นที่หากไม่มีข้อจำกัด Text
minIntrinsicHeight
จะเป็นของข้อความที่ระบุ 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