กฎข้อหนึ่งของ 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