การวัดภายในในเลย์เอาต์ของ Compose

กฎข้อหนึ่งของ Compose คือคุณควรวัดค่าของบุตรหลานเพียงครั้งเดียวเท่านั้น การวัดค่าบุตรหลาน 2 ครั้งจะทำให้เกิดข้อยกเว้นรันไทม์ อย่างไรก็ตาม บางครั้งคุณก็จำเป็นต้องทราบข้อมูลบางอย่างเกี่ยวกับบุตรหลานก่อนทำการวัด

ข้อมูลพื้นฐานช่วยให้คุณค้นหาข้อมูลเกี่ยวกับเด็กได้ก่อนที่จะมีการวัดผลจริง

คุณสามารถขอ IntrinsicSize.Min หรือ IntrinsicSize.Max ของคอมโพสิเบิลได้โดยทำดังนี้

  • Modifier.width(IntrinsicSize.Min) - คุณต้องแสดงเนื้อหาในขนาดความกว้างขั้นต่ำเท่าใดจึงจะเหมาะสม
  • Modifier.width(IntrinsicSize.Max) - คุณต้องกำหนดความกว้างสูงสุดเท่าใดจึงจะแสดงเนื้อหาได้อย่างถูกต้อง
  • Modifier.height(IntrinsicSize.Min) - คุณต้องกำหนดความสูงขั้นต่ำเท่าใดเพื่อแสดงเนื้อหาอย่างเหมาะสม
  • Modifier.height(IntrinsicSize.Max) - คุณต้องการความสูงสูงสุดเท่าใดเพื่อแสดงเนื้อหาอย่างเหมาะสม

เช่น หากคุณถาม minIntrinsicHeight ของ Text ที่มีข้อจำกัด width แบบไม่จำกัดในเลย์เอาต์ที่กำหนดเอง ระบบจะแสดงผล height ของ Text ที่มีข้อความที่วาดเป็นบรรทัดเดียว

การใช้งาน Intrinsics

สมมติว่าเราต้องการสร้างคอมโพสิเบิลที่แสดงข้อความ 2 รายการบนหน้าจอโดยคั่นด้วยตัวแบ่ง เช่นนี้

องค์ประกอบข้อความ 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 ขยายเต็มหน้าจอ ซึ่งไม่ใช่สิ่งที่เราต้องการ

องค์ประกอบข้อความ 2 รายการอยู่เคียงข้างกันโดยมีตัวแบ่งคั่นระหว่างกลาง แต่ตัวแบ่งนั้นยืดลงไปด้านล่างของข้อความ

ปัญหานี้เกิดขึ้นเนื่องจาก 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")
        }
    }
}

เมื่อใช้ฟีเจอร์แสดงตัวอย่าง

องค์ประกอบข้อความ 2 รายการอยู่ข้างกันโดยมีตัวแบ่งแนวตั้งคั่นระหว่างกลาง

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.
}

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 18, 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 18, 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 18, 2025