รายการแบบ Lazy ในตารางกริด

ไอคอนการให้ดาว 4 ดวง

Composable Grid จะสร้างเลย์เอาต์หน้าจอแบบ 2 มิติที่มีโครงสร้าง Grid กำหนดโครงสร้างเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์โดยใช้แทร็ก (แถวและคอลัมน์) และช่องว่างที่กำหนดไว้อย่างชัดเจนเป็นสถาปัตยกรรมพื้นฐานของ UI

เนื่องจาก Grid เป็นคอนเทนเนอร์เชิงโครงสร้าง ไม่ใช่คอนเทนเนอร์แบบ Lazy Loading คุณจึงต้องกำหนดองค์ประกอบทุกรายการที่วางไว้ภายในอย่างชัดเจนโดยไม่ต้องรีไซเคิลรายการเมื่อเลื่อน ด้วยเหตุนี้ การแสดงผลชุดข้อมูลขนาดใหญ่หรือแบบไดนามิกภายใน Grid โดยตรงจึงอาจทำให้เกิดคอขวดด้านประสิทธิภาพเนื่องจากรายการทั้งหมดจะคอมโพสพร้อมกัน

หากต้องการแสดงคอลเล็กชันข้อมูลขนาดใหญ่ภายในเลย์เอาต์หน้าจอที่มีโครงสร้าง ให้ฝังคอมโพเนนต์แบบ Lazy เช่น LazyColumn หรือ LazyRow ในเซลล์ Grid แต่โปรดทราบว่าแทร็กที่ยืดหยุ่น (ซึ่งมีข้อกำหนด เช่น 1.fr) จะค้นหาขนาดที่แท้จริงขององค์ประกอบย่อย เนื่องจาก SubcomposeLayout ไม่รองรับการส่งผ่านการวัดค่าภายใน การวางรายการแบบ Lazy ภายในแทร็กที่ยืดหยุ่นจึงทำให้เกิดข้อขัดข้อง IllegalStateException หากต้องการวางรายการแบบ Lazy ภายในแทร็กตารางกริดแบบยืดหยุ่นอย่างปลอดภัย คุณต้องใช้การปรับขนาด GridTrackSize.MinMax (เช่น minmax(0.dp, 1.fr)) เพื่อข้ามขั้นตอนการวัดค่าภายใน

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

แนวทางปฏิบัติแนะนำ

  • ใช้ Lazy List แทนลูปที่ชัดเจนขนาดใหญ่: หากต้องการแสดงชุดข้อมูลขนาดใหญ่หรือแบบไดนามิกภายใน Grid ที่มีโครงสร้าง ให้ฝังคอมโพเนนต์ Lazy (โดยทั่วไปคือ LazyColumn หรือ LazyRow) ไว้ภายในเซลล์ตารางกริดที่เฉพาะเจาะจง แทนที่จะสร้างลูปที่ชัดเจนขนาดใหญ่เหนือรายการ เนื่องจาก Grid ไม่รีไซเคิลรายการและมีขีดจำกัดที่ 1,000 แทร็ก
  • ใช้การปรับขนาดแทร็ก MinMax สำหรับ Lazy List: เนื่องจาก LazyColumn และ LazyRow ไม่รองรับการส่งผ่านการวัดภายใน (ดู SubcomposeLayout) ให้ใช้ GridTrackSize.MinMax ในแทร็กที่ยืดหยุ่นซึ่งโฮสต์คอมโพเนนต์ Lazy เพื่อข้ามการวัดภายในอย่างปลอดภัย

ส่วนผสม

  • Grid: เลย์เอาต์ Composable ที่วางรายการในโครงสร้างตารางกริด 2 มิติซึ่งกำหนดค่าโดยใช้แทร็กแถวและคอลัมน์ที่ชัดเจน
  • LazyColumn: รายการที่เลื่อนในแนวตั้งซึ่งเขียนและรีไซเคิลเฉพาะรายการที่มองเห็นได้บนหน้าจอในขณะนั้น
  • GridTrackSize.MinMax: พร็อพเพอร์ตี้การปรับขนาดแทร็กที่กำหนดขอบเขตที่ยืดหยุ่น (min และ max) เพื่อโฮสต์คอมโพเนนต์แบบ Lazy ได้อย่างปลอดภัยโดยไม่ทำให้เกิดข้อขัดข้องในการวัดรันไทม์
  • gridItem: ส่วนขยาย Compose Modifier ที่กำหนดองค์ประกอบ UI ย่อยให้กับเซลล์ที่เฉพาะเจาะจงหรือพื้นที่ที่มีชื่อภายใน Grid

ขั้นตอน

จัดโครงสร้างเลย์เอาต์หน้าจอโดยกำหนดตัวระบุพื้นที่เชิงความหมาย กำหนดค่าแทร็กตารางกริดด้วยการปรับขนาด minmax เพื่อให้เข้ากันได้กับ Lazy List และฝัง LazyColumn ไว้ในพื้นที่เนื้อหาตารางกริด

1. กำหนดค่าแทร็กตารางกริดและพื้นที่ที่มีชื่อ

สร้างคลาส enum เพื่อแสดงถึงพื้นที่ต่างๆ ของเลย์เอาต์หน้าจอ และกำหนดแลมบ์ดา GridConfigurationScope สำหรับแทร็กเลย์เอาต์และพื้นที่ที่มีชื่อ ใช้ GridTrackSize.MaxContent สำหรับแถวส่วนหัวและส่วนท้ายเพื่อให้พอดีกับขนาดเนื้อหา และใช้ minmax(0.dp, 1.fr) สำหรับแทร็กเนื้อหาที่โฮสต์รายการแบบ Lazy เพื่อจัดสรรพื้นที่ที่ยืดหยุ่นโดยไม่ต้องค้นหาการวัดค่าภายในที่ไม่รองรับ ดังนี้

enum class ScreenArea {
    Header,
    Content,
    Footer
}


val lazyConfig: GridConfigurationScope.() -> Unit = {
    column(minmax(0.dp, 1.fr))
    row(GridTrackSize.MaxContent)
    row(minmax(0.dp, 1.fr))
    row(GridTrackSize.MaxContent)

    area(ScreenArea.Header, row = 1, column = 1)
    area(ScreenArea.Content, row = 2, column = 1)
    area(ScreenArea.Footer, row = 3, column = 1)
    gap(8.dp)
}

2. วางคอมโพเนนต์แบบคงที่ในตารางกริด

ใน Composable ให้ส่ง lazyConfig ไปยังคอนเทนเนอร์ Grid ภายในแลมบ์ดา content ให้วางคอมโพเนนต์แบบคงที่ (Header และ Footer) และจัดตำแหน่งโดยใช้ Modifier.gridItem() พร้อมตัวระบุพื้นที่ที่เกี่ยวข้อง

3. ฝัง LazyColumn ในพื้นที่เนื้อหา

ฝัง LazyColumn โดยใช้ Modifier.gridItem(ScreenArea.Content) ในเซลล์เนื้อหา เนื่องจากมีการกำหนดค่าแทร็กเนื้อหาด้วย minmax(0.dp, 1.fr) ในขั้นตอนที่ 1 LazyColumn จึงสามารถวัดและรีไซเคิลรายการเมื่อเลื่อนได้อย่างปลอดภัยโดยไม่ต้องค้นหามิติข้อมูลภายในที่ไม่รองรับ ดังนี้

@Composable
fun GridWithLazyColumn(
    modifier: Modifier = Modifier,
    items: List<String> = emptyList(),
) {
    Grid(
        modifier = modifier.fillMaxSize(),
        config = lazyConfig
    ) {
        Text("Header", Modifier.gridItem(ScreenArea.Header).padding(16.dp))
        Text("Footer", Modifier.gridItem(ScreenArea.Footer).padding(16.dp))

        // LazyColumn placed in the content area for large datasets
        LazyColumn(
            modifier = Modifier
                .gridItem(ScreenArea.Content)
                .fillMaxSize(),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            items(items) { item ->
                Text(item, Modifier.padding(16.dp))
            }
        }
    }
}

ผลลัพธ์

ตอนนี้เลย์เอาต์หน้าจอของคุณใช้ Grid API เพื่อกำหนดโครงสร้างหน้าเว็บแบบ 2 มิติโดยรวม ขณะที่ฝัง LazyColumn ในแทร็กที่ยืดหยุ่นด้วยการปรับขนาด minmax เพื่อรีไซเคิลรายการในลิสต์อย่างมีประสิทธิภาพและหลีกเลี่ยงข้อยกเว้นรันไทม์

แหล่งข้อมูลเพิ่มเติม