เลย์เอาต์ที่กำหนดเอง

ใน Compose องค์ประกอบ UI จะแสดงด้วยฟังก์ชันที่ประกอบกันได้ซึ่งจะปล่อย UI ออกมาเมื่อมีการเรียกใช้ จากนั้นจะเพิ่มลงในแผนผัง UI ที่แสดงผลบนหน้าจอ องค์ประกอบ UI แต่ละรายการจะมีองค์ประกอบหลัก 1 รายการและอาจมีองค์ประกอบย่อยหลายรายการ นอกจากนี้ องค์ประกอบแต่ละรายการจะอยู่ในองค์ประกอบหลัก โดยระบุเป็นตำแหน่ง (x, y) และขนาดที่ระบุเป็น width และ height

องค์ประกอบหลักจะกำหนดข้อจำกัดสำหรับองค์ประกอบย่อย ระบบจะขอให้องค์ประกอบกำหนดขนาดภายในข้อจำกัดเหล่านั้น ข้อจำกัดจะจำกัด width และ height ขั้นต่ำและสูงสุดขององค์ประกอบ หากองค์ประกอบมีองค์ประกอบย่อย องค์ประกอบนั้นอาจวัดขนาดขององค์ประกอบย่อยแต่ละรายการเพื่อช่วยกำหนดขนาดของตัวเอง เมื่อองค์ประกอบกำหนด และรายงานขนาดของตัวเองแล้ว องค์ประกอบนั้นจะมีโอกาสกำหนดวิธีวางองค์ประกอบย่อย ที่สัมพันธ์กับตัวเองตามที่อธิบายไว้โดยละเอียดในหัวข้อการสร้างเลย์เอาต์ ที่กำหนดเอง

การจัดวางโหนดแต่ละโหนดในแผนผัง UI เป็นกระบวนการ 3 ขั้นตอน โดยแต่ละโหนดต้องทำดังนี้

  1. วัดขนาดขององค์ประกอบย่อย
  2. กำหนดขนาดของตัวเอง
  3. วางองค์ประกอบย่อย
ขั้นตอนที่ 3 ของเลย์เอาต์โหนด: วัดขนาดของโหนดย่อย กำหนดขนาด และวางโหนดย่อย
รูปที่ 1 ขั้นตอนที่ 3 ของการจัดวางโหนดคือการวัดขนาดขององค์ประกอบย่อย การกำหนดขนาด และการวางองค์ประกอบย่อย

การใช้ขอบเขตจะกำหนด เวลา ที่คุณวัดขนาดและวางองค์ประกอบย่อยได้ การวัดขนาดเลย์เอาต์จะทำได้เฉพาะในระหว่างการวัดและการจัดวาง และจะวางองค์ประกอบย่อยได้เฉพาะในระหว่างการจัดวาง (และหลังจากวัดขนาดแล้วเท่านั้น) ระบบจะบังคับใช้ข้อจำกัดนี้ในเวลาคอมไพล์เนื่องจากขอบเขตของ Compose เช่น MeasureScope, และ PlacementScope,

ใช้ตัวปรับแต่งเลย์เอาต์

คุณสามารถใช้ตัวปรับแต่ง layout เพื่อปรับเปลี่ยนวิธีวัดขนาดและจัดวางองค์ประกอบ Layout เป็นแลมบ์ดา โดยพารามิเตอร์ของแลมบ์ดาประกอบด้วยองค์ประกอบที่คุณวัดขนาดได้ ซึ่งส่งผ่านเป็น measurable และข้อจำกัดขาเข้าของ Composable นั้น ซึ่งส่งผ่านเป็น constraints ตัวปรับแต่งเลย์เอาต์ที่กำหนดเองอาจมีลักษณะดังนี้

fun Modifier.customLayoutModifier() =
    layout { measurable, constraints ->
        // ...
    }

แสดง Text บนหน้าจอและควบคุมระยะห่างจากด้านบนถึงเส้นฐานของข้อความบรรทัดแรก ตัวปรับแต่ง paddingFromBaseline จะทำหน้าที่นี้พอดีเป๊ะ โดยเราจะใช้ตัวปรับแต่งนี้เป็นตัวอย่าง หากต้องการทำเช่นนั้น ให้ใช้ตัวปรับแต่ง layout เพื่อวาง Composable บนหน้าจอด้วยตนเอง นี่คือลักษณะการทำงานที่ได้เมื่อตั้งค่าระยะห่างจากด้านบนของ Text เป็น 24.dp

แสดงความแตกต่างระหว่างระยะเว้นขอบ UI ปกติ ซึ่งกำหนดช่องว่างระหว่างองค์ประกอบ กับระยะเว้นขอบข้อความ ซึ่งกำหนดช่องว่างจากบรรทัดฐานหนึ่งไปยังอีกบรรทัดหนึ่ง
รูปที่ 2 ข้อความที่มีการใช้ paddingFromBaseline

นี่คือโค้ดที่ใช้สร้างระยะห่างดังกล่าว

fun Modifier.firstBaselineToTop(
    firstBaselineToTop: Dp
) = layout { measurable, constraints ->
    // Measure the composable
    val placeable = measurable.measure(constraints)

    // Check the composable has a first baseline
    check(placeable[FirstBaseline] != AlignmentLine.Unspecified)
    val firstBaseline = placeable[FirstBaseline]

    // Height of the composable with padding - first baseline
    val placeableY = firstBaselineToTop.roundToPx() - firstBaseline
    val height = placeable.height + placeableY
    layout(placeable.width, height) {
        // Where the composable gets placed
        placeable.placeRelative(0, placeableY)
    }
}

โค้ดดังกล่าวจะทำงานดังนี้

  1. ในพารามิเตอร์แลมบ์ดา measurable คุณจะวัดขนาด Text ที่แสดงด้วย พารามิเตอร์ measurable โดยเรียกใช้ measurable.measure(constraints)
  2. คุณระบุขนาดของ Composable โดยเรียกใช้เมธอด layout(width, height) ซึ่งจะให้แลมบ์ดาที่ใช้สำหรับวางองค์ประกอบที่ห่อไว้ด้วย ในกรณีนี้คือความสูงระหว่างเส้นฐานสุดท้ายกับระยะห่างจากด้านบนที่เพิ่มเข้ามา
  3. คุณวางองค์ประกอบที่ห่อไว้บนหน้าจอโดยเรียกใช้ placeable.place(x, y) หากไม่ได้วางองค์ประกอบที่ห่อไว้ องค์ประกอบเหล่านั้นจะไม่ปรากฏ ตำแหน่ง y จะสอดคล้องกับระยะห่างจากด้านบน ซึ่งเป็นตำแหน่งของเส้นฐานแรกของข้อความ

หากต้องการยืนยันว่าตัวปรับแต่งนี้ทำงานตามที่คาดไว้ ให้ใช้ตัวปรับแต่งนี้กับ Text

@Preview
@Composable
fun TextWithPaddingToBaselinePreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.firstBaselineToTop(32.dp))
    }
}

@Preview
@Composable
fun TextWithNormalPaddingPreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.padding(top = 32.dp))
    }
}

ตัวอย่างองค์ประกอบข้อความหลายรายการ โดยรายการหนึ่งแสดงระยะห่างปกติระหว่างองค์ประกอบ ส่วนอีกรายการแสดงระยะห่างจากบรรทัดฐานหนึ่งไปยังอีกบรรทัดฐานหนึ่ง
รูปที่ 3 ตัวปรับแต่งที่ใช้กับ Composable Text และแสดงตัวอย่าง

สร้างเลย์เอาต์ที่กำหนดเอง

ตัวปรับแต่ง layout จะเปลี่ยนเฉพาะ Composable ที่เรียกใช้ หากต้องการวัดขนาดและจัดวาง Composable หลายรายการ ให้ใช้ Layout แทน Composable นี้ช่วยให้คุณวัดขนาดและจัดวางองค์ประกอบย่อยด้วยตนเองได้ เลย์เอาต์ระดับสูงทั้งหมด เช่น Column และ Row สร้างขึ้นด้วย Composable Layout

ตัวอย่างนี้สร้าง Column เวอร์ชันพื้นฐานมาก เลย์เอาต์ที่กำหนดเองส่วนใหญ่จะมีลักษณะดังนี้

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // measure and position children given constraints logic here
        // ...
    }
}

measurables เป็นรายการองค์ประกอบย่อยที่ต้องวัดขนาด และ constraints เป็นข้อจำกัดจากองค์ประกอบหลัก ซึ่งคล้ายกับตัวปรับแต่ง layout MyBasicColumn สามารถใช้ได้ดังนี้ โดยใช้ตรรกะเดียวกับก่อนหน้านี้

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // Don't constrain child views further, measure them with given constraints
        // List of measured children
        val placeables = measurables.map { measurable ->
            // Measure each children
            measurable.measure(constraints)
        }

        // Set the size of the layout as big as it can
        layout(constraints.maxWidth, constraints.maxHeight) {
            // Track the y co-ord we have placed children up to
            var yPosition = 0

            // Place children in the parent layout
            placeables.forEach { placeable ->
                // Position item on the screen
                placeable.placeRelative(x = 0, y = yPosition)

                // Record the y co-ord placed up to
                yPosition += placeable.height
            }
        }
    }
}

Composable องค์ประกอบย่อยจะถูกจำกัดด้วยข้อจำกัด Layout (ไม่มีข้อจำกัด minHeight) และจะวางตาม yPosition ของ Composable ก่อนหน้า

วิธีใช้ Composable ที่กำหนดเอง

@Composable
fun CallingComposable(modifier: Modifier = Modifier) {
    MyBasicColumn(modifier.padding(8.dp)) {
        Text("MyBasicColumn")
        Text("places items")
        Text("vertically.")
        Text("We've done it by hand!")
    }
}

องค์ประกอบข้อความหลายรายการซ้อนกันในคอลัมน์
รูปที่ 4 การใช้ Column ที่กำหนดเอง

ทิศทางการจัดวาง

เปลี่ยนทิศทางการจัดวางของ Composable โดยเปลี่ยน LocalLayoutDirection องค์ประกอบภายใน

หากคุณวาง Composable บนหน้าจอด้วยตนเอง LayoutDirection จะเป็น ส่วนหนึ่งของ LayoutScope ของตัวปรับแต่ง layout หรือ Composable Layout

เมื่อใช้ layoutDirection ให้วาง Composable โดยใช้ place ซึ่งแตกต่างจากเมธอด placeRelative place จะไม่เปลี่ยนแปลงตามทิศทางการจัดวาง (จากซ้ายไปขวาเทียบกับจากขวาไปซ้าย)

เลย์เอาต์ที่กำหนดเองในการใช้งานจริง

ดูข้อมูลเพิ่มเติมเกี่ยวกับเลย์เอาต์และตัวปรับแต่งได้ใน หัวข้อเลย์เอาต์พื้นฐานใน Compose, และดูเลย์เอาต์ที่กำหนดเองในการใช้งานจริงได้ใน ตัวอย่าง Compose ที่สร้างเลย์เอาต์ที่กำหนดเอง

ดูข้อมูลเพิ่มเติม

หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับเลย์เอาต์ที่กำหนดเองใน Compose โปรดดูแหล่งข้อมูลเพิ่มเติมต่อไปนี้

วิดีโอ