กฎข้อหนึ่งของ Compose คือคุณควรวัดค่าของบุตรหลานเพียงครั้งเดียวเท่านั้น การวัดค่าบุตรหลาน 2 ครั้งจะทำให้เกิดข้อยกเว้นรันไทม์ อย่างไรก็ตาม บางครั้งคุณก็จำเป็นต้องทราบข้อมูลบางอย่างเกี่ยวกับบุตรหลานก่อนทำการวัด
Intrinsics ช่วยให้คุณค้นหาเด็กๆ ได้ก่อนที่จะมีการวัดผลจริง
คุณสามารถขอ intrinsicWidth
หรือ intrinsicHeight
ของคอมโพสิเบิลได้โดยทำดังนี้
(min|max)IntrinsicWidth
: ในกรณีนี้ คุณจะวาดเนื้อหาได้อย่างถูกต้องโดยใช้ความกว้างขั้นต่ำ/สูงสุดเท่าใด(min|max)IntrinsicHeight
: เมื่อใช้ความสูงนี้ ความสูงขั้นต่ำ/สูงสุดที่คุณวาดเนื้อหาได้อย่างถูกต้องคือเท่าใด
เช่น หากคุณถาม minIntrinsicHeight
ของ Text
ที่มี height
แบบไม่จำกัด ระบบจะแสดงผล height
ของ Text
ราวกับว่ามีการวาดข้อความเป็นบรรทัดเดียว
การใช้งาน Intrinsics
สมมติว่าเราต้องการสร้างคอมโพสิเบิลที่แสดงข้อความ 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 ) HorizontalDivider( 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 ) HorizontalDivider( 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") } } }
เมื่อใช้ฟีเจอร์แสดงตัวอย่าง
minIntrinsicHeight
ของคอมโพสิเบิล Row
จะเป็นminIntrinsicHeight
สูงสุดของบุตรหลาน minIntrinsicHeight
ขององค์ประกอบ Divider
คือ 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