เลย์เอาต์โฟลว์ใน Compose

FlowRow และ FlowColumn เป็น Composable ที่คล้ายกับ Row และ Column แต่ต่างกันที่รายการ เข้าไปในบรรทัดถัดไปเมื่อคอนเทนเนอร์ไม่มีพื้นที่เหลือ การดำเนินการนี้จะสร้าง หลายแถวหรือหลายคอลัมน์ คุณควบคุมจำนวนรายการในบรรทัดได้ด้วย โดยการตั้งค่า maxItemsInEachRow หรือ maxItemsInEachColumn คุณมักจะใช้ FlowRow และ FlowColumn เพื่อสร้างเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ ระบบจะไม่ตัดเนื้อหาออก ปิด หากรายการใหญ่เกินไปสำหรับมิติข้อมูลหนึ่งและใช้ชุดค่าผสมของ maxItemsInEach* ที่มี Modifier.weight(weight) สามารถช่วยสร้างเลย์เอาต์ที่ เติม/ขยายความกว้างของแถวหรือคอลัมน์เมื่อจำเป็น

ตัวอย่างโดยทั่วไปสำหรับชิปหรือ UI การกรอง

วันที่ ชิป 5 รายการใน FlowRow แสดงส่วนเกินไปยังบรรทัดถัดไปเมื่อไม่มี
มีพื้นที่ว่างมากขึ้น
รูปที่ 1 ตัวอย่างของ FlowRow

การใช้งานพื้นฐาน

หากต้องการใช้ FlowRow หรือ FlowColumn ให้สร้าง Composable เหล่านี้และวางรายการ ซึ่งควรเป็นไปตามขั้นตอนมาตรฐาน

@Composable
private fun FlowRowSimpleUsageExample() {
    FlowRow(modifier = Modifier.padding(8.dp)) {
        ChipItem("Price: High to Low")
        ChipItem("Avg rating: 4+")
        ChipItem("Free breakfast")
        ChipItem("Free cancellation")
        ChipItem("£50 pn")
    }
}

ข้อมูลโค้ดนี้ส่งผลกับ UI ที่แสดงอยู่ด้านบน โดยจะมีรายการต่างๆ ไหลไปที่ แถวถัดไปหากไม่มีพื้นที่เหลือในแถวแรก

ฟีเจอร์ของเลย์เอาต์โฟลว์

เลย์เอาต์โฟลว์มีฟีเจอร์และพร็อพเพอร์ตี้ดังต่อไปนี้ที่คุณใช้เพื่อ สร้างเลย์เอาต์ที่แตกต่างกันในแอป

การจัดเรียงแกนหลัก: การจัดเรียงแนวนอนหรือแนวตั้ง

แกนหลักคือแกนที่มีการวางรายการ (ตัวอย่างเช่น FlowRow จัดเรียงรายการในแนวนอน) horizontalArrangement ใน FlowRow จะควบคุมวิธีกระจายพื้นที่ว่างระหว่างรายการต่างๆ

ตารางต่อไปนี้แสดงตัวอย่างการตั้งค่า horizontalArrangement ในรายการ สำหรับ FlowRow:

ตั้งค่าการจัดเรียงแนวนอนตาม FlowRow

ผลลัพธ์

Arrangement.Start (Default)

รายการที่จัดเรียงตามจุดเริ่มต้น

Arrangement.SpaceBetween

การจัดเรียงรายการที่มีพื้นที่อยู่ระหว่าง

Arrangement.Center

จัดอยู่กึ่งกลาง

Arrangement.End

รายการที่จัดเรียงไว้ท้ายสุด

Arrangement.SpaceAround

จัดเรียงสิ่งของโดยมีพื้นที่รอบๆ

Arrangement.spacedBy(8.dp)

รายการที่เว้นระยะห่างด้วย dp ที่กำหนด

สำหรับ FlowColumn ตัวเลือกที่คล้ายกันมีให้ใช้งานใน verticalArrangement โดย ค่าเริ่มต้นคือ Arrangement.Top

การจัดเรียงแกนไขว้

แกนกากบาทคือแกนในทิศทางตรงกันข้ามกับแกนหลัก สำหรับ ตัวอย่างเช่น ใน FlowRow นี่คือแกนแนวตั้ง เพื่อเปลี่ยนลักษณะโดยรวม สิ่งที่อยู่ในคอนเทนเนอร์จะอยู่ในแกนกากบาท verticalArrangement สำหรับ FlowRow และ horizontalArrangement สำหรับ FlowColumn

สำหรับ FlowRow ตารางต่อไปนี้จะแสดงตัวอย่างการตั้งค่าแบบต่างๆ verticalArrangement ในรายการ:

ตั้งค่าการจัดเรียงแนวตั้งเมื่อวันที่ FlowRow

ผลลัพธ์

Arrangement.Top (Default)

การจัดเรียงด้านบนของคอนเทนเนอร์

Arrangement.Bottom

การจัดเรียงด้านล่างของคอนเทนเนอร์

Arrangement.Center

การจัดเรียงศูนย์คอนเทนเนอร์

สำหรับ FlowColumn ตัวเลือกที่คล้ายกันจะใช้งานได้ใน horizontalArrangement การจัดเรียงข้ามแกนตามค่าเริ่มต้นคือ Arrangement.Start

การจัดข้อความทีละรายการ

คุณอาจต้องการจัดตำแหน่งแต่ละรายการภายในแถวด้วย การจัดแนว ซึ่งแตกต่างจาก verticalArrangement และ horizontalArrangement เนื่องจากปรับแนวรายการภายในบรรทัดปัจจุบัน คุณสามารถ ให้ใช้ตัวเลือกนี้กับ Modifier.align()

ตัวอย่างเช่น เมื่อรายการใน FlowRow มีความสูงต่างกัน แถวจะนำแอตทริบิวต์ ความสูงของรายการที่ใหญ่ที่สุดและใช้ Modifier.align(alignmentOption) กับองค์ประกอบ รายการ:

ตั้งค่าการจัดข้อความแนวตั้งใน FlowRow

ผลลัพธ์

Alignment.Top (Default)

รายการที่จัดชิดด้านบน

Alignment.Bottom

รายการที่จัดชิดด้านล่าง

Alignment.CenterVertically

รายการที่จัดชิดกึ่งกลาง

สำหรับ FlowColumn มีตัวเลือกที่คล้ายกันพร้อมให้บริการ การจัดข้อความเริ่มต้นคือ Alignment.Start

จำนวนรายการสูงสุดในแถวหรือคอลัมน์

พารามิเตอร์ maxItemsInEachRow หรือ maxItemsInEachColumn กำหนดขีดจำกัดสูงสุด รายการในแกนหลักให้แสดงใน 1 บรรทัดก่อนที่จะตัดไปยังรายการถัดไป ค่าเริ่มต้นคือ Int.MAX_INT ซึ่งจะอนุญาตรายการมากที่สุดเท่าที่จะเป็นไปได้ ตราบใดที่ เพื่อให้พอดีกับเส้น

เช่น การตั้งค่า maxItemsInEachRow จะบังคับให้เลย์เอาต์เริ่มต้นเหลือเพียง มี 3 รายการ:

ไม่ได้ตั้งค่าสูงสุด

maxItemsInEachRow = 3

ไม่ได้กำหนดค่าสูงสุดในแถวโฟลว์ จำนวนรายการสูงสุดที่กำหนดไว้ในแถวโฟลว์

รายการขั้นตอนการโหลดแบบ Lazy Loading

ContextualFlowRow และ ContextualFlowColumn เป็น FlowRow และ FlowColumn เวอร์ชันที่ช่วยให้คุณโหลดเนื้อหาแบบ Lazy Loading ได้ ของแถวหรือคอลัมน์โฟลว์ และยังให้ข้อมูลเกี่ยวกับตำแหน่งรายการ (ดัชนี หมายเลขแถว และขนาดที่ใช้ได้) เช่น หากรายการนั้นอยู่ในรายการแรก แถว ซึ่งจะเป็นประโยชน์สำหรับชุดข้อมูลขนาดใหญ่และในกรณีที่คุณต้องการข้อมูลตามบริบท เกี่ยวกับรายการ

พารามิเตอร์ maxLines จะจำกัดจำนวนแถวที่แสดง และ overflow จะระบุสิ่งที่ควรแสดงเมื่อมีรายการเพิ่มเติม เข้าถึง ทำให้คุณสามารถระบุ expandIndicator ที่กำหนดเองหรือ collapseIndicator

ตัวอย่างเช่น เพื่อแสดงเครื่องหมาย "+ (จำนวนรายการที่เหลือ)" หรือ "แสดงน้อยลง" ปุ่ม:

val totalCount = 40
var maxLines by remember {
    mutableStateOf(2)
}

val moreOrCollapseIndicator = @Composable { scope: ContextualFlowRowOverflowScope ->
    val remainingItems = totalCount - scope.shownItemCount
    ChipItem(if (remainingItems == 0) "Less" else "+$remainingItems", onClick = {
        if (remainingItems == 0) {
            maxLines = 2
        } else {
            maxLines += 5
        }
    })
}
ContextualFlowRow(
    modifier = Modifier
        .safeDrawingPadding()
        .fillMaxWidth(1f)
        .padding(16.dp)
        .wrapContentHeight(align = Alignment.Top)
        .verticalScroll(rememberScrollState()),
    verticalArrangement = Arrangement.spacedBy(4.dp),
    horizontalArrangement = Arrangement.spacedBy(8.dp),
    maxLines = maxLines,
    overflow = ContextualFlowRowOverflow.expandOrCollapseIndicator(
        minRowsToShowCollapse = 4,
        expandIndicator = moreOrCollapseIndicator,
        collapseIndicator = moreOrCollapseIndicator
    ),
    itemCount = totalCount
) { index ->
    ChipItem("Item $index")
}

วันที่ ตัวอย่างแถวโฟลว์ตามบริบท
รูปที่ 2 ตัวอย่างของ ContextualFlowRow

น้ำหนักสินค้า

น้ำหนักจะเพิ่มขนาดสินค้าตามปัจจัยและพื้นที่ว่างบนเส้น วาง ใน ที่สำคัญมีความแตกต่างระหว่าง FlowRow และ Row กับวิธีการใช้น้ำหนักในการคำนวณความกว้างของสิ่งของ สำหรับ Rows น้ำหนัก อิงตามรายการทั้งหมดในRow สำหรับ FlowRow น้ำหนักจะอิงตาม รายการในบรรทัดที่มีการวางรายการ ไม่ใช่รายการทั้งหมดใน คอนเทนเนอร์ FlowRow

ตัวอย่างเช่น หากคุณมีสินค้า 4 รายการ ซึ่งแต่ละรายการจะไม่เหมือนกัน น้ำหนัก 1f, 2f, 1f และ 3f น้ำหนักรวมคือ 7f พื้นที่ที่เหลือ ในแถวหรือคอลัมน์จะถูกหารด้วย 7f จากนั้น ความกว้างของแต่ละรายการจะเป็น คำนวณโดยใช้: weight * (remainingSpace / totalWeight)

คุณสามารถใช้ทั้ง Modifier.weight รายการและสูงสุดร่วมกับ FlowRow หรือ FlowColumn เพื่อสร้างเลย์เอาต์ที่เหมือนตารางกริด วิธีนี้มีประโยชน์ในการสร้าง เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ซึ่งปรับให้เข้ากับขนาดของอุปกรณ์

มีตัวอย่าง 2-3 ตัวอย่างของสิ่งที่คุณจะได้รับจากการใช้การถ่วงน้ำหนัก หนึ่ง ตัวอย่างเช่น ตารางกริดที่รายการมีขนาดเท่ากัน ตามที่แสดงด้านล่าง

วันที่ สร้างตารางกริดที่มีแถวโฟลว์แล้ว
รูปที่ 3 การใช้ FlowRow เพื่อสร้างตารางกริด

หากต้องการสร้างตารางกริดที่มีขนาดรายการเท่ากัน คุณจะทําสิ่งต่อไปนี้ได้

val rows = 3
val columns = 3
FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = rows
) {
    val itemModifier = Modifier
        .padding(4.dp)
        .height(80.dp)
        .weight(1f)
        .clip(RoundedCornerShape(8.dp))
        .background(MaterialColors.Blue200)
    repeat(rows * columns) {
        Spacer(modifier = itemModifier)
    }
}

ที่สำคัญ หากคุณเพิ่มอีกรายการหนึ่งและทำซ้ำ 10 ครั้งแทนที่จะเป็น 9 ครั้ง รายการสุดท้ายครอบคลุมคอลัมน์สุดท้ายทั้งคอลัมน์ เป็นน้ำหนักรวมของทั้งแถว เท่ากับ 1f:

วันที่ รายการสุดท้ายขนาดเต็มในตาราง
รูปที่ 4 ใช้ FlowRow เพื่อสร้างตารางกริดที่มีรายการสุดท้ายเต็มความกว้าง

คุณสามารถรวมน้ำหนักกับ Modifiers อื่นๆ ได้ เช่น Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio) หรือ Modifier.fillMaxWidth(fraction) ตัวปรับแต่งเหล่านี้ทั้งหมดจะทำงานร่วมกับ อนุญาตให้ใช้การปรับขนาดของรายการต่างๆ ภายใน FlowRow (หรือ FlowColumn)

นอกจากนี้ คุณยังสร้างตารางกริดแบบสลับรายการขนาดต่างๆ ได้โดยที่รายการ 2 รายการ ใช้ความกว้างครึ่งหนึ่งของแต่ละรายการ และรายการหนึ่งใช้ความกว้างเต็มของถัดไป คอลัมน์:

วันที่ ตารางกริดสลับกับแถวโฟลว์
รูปที่ 5 FlowRow ที่มีขนาดสลับกันของแถว

คุณสามารถทำได้โดยใช้โค้ดต่อไปนี้

FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = 2
) {
    val itemModifier = Modifier
        .padding(4.dp)
        .height(80.dp)
        .clip(RoundedCornerShape(8.dp))
        .background(Color.Blue)
    repeat(6) { item ->
        // if the item is the third item, don't use weight modifier, but rather fillMaxWidth
        if ((item + 1) % 3 == 0) {
            Spacer(modifier = itemModifier.fillMaxWidth())
        } else {
            Spacer(modifier = itemModifier.weight(0.5f))
        }
    }
}

การปรับขนาดเป็นเศษส่วน

เมื่อใช้ Modifier.fillMaxWidth(fraction) คุณสามารถระบุขนาดของฟิลด์ คอนเทนเนอร์ที่รายการจะใช้ ซึ่งแตกต่างจาก Modifier.fillMaxWidth(fraction) ทำงานเมื่อใช้กับ Row หรือ Column ใน ว่า Row/Column รายการใช้เปอร์เซ็นต์ของความกว้างที่เหลือมากกว่า ความกว้างของคอนเทนเนอร์ทั้งหมด

ตัวอย่างเช่น โค้ดต่อไปนี้จะสร้างผลลัพธ์ที่แตกต่างกันเมื่อใช้ FlowRow เทียบกับ Row:

FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = 3
) {
    val itemModifier = Modifier
        .clip(RoundedCornerShape(8.dp))
    Box(modifier = itemModifier.height(200.dp).width(60.dp).background(Color.Red))
    Box(modifier = itemModifier.height(200.dp).fillMaxWidth(0.7f).background(Color.Blue))
    Box(modifier = itemModifier.height(200.dp).weight(1f).background(Color.Magenta))
}

FlowRow: รายการตรงกลางที่มีเศษส่วน 0.7 ของความกว้างคอนเทนเนอร์ทั้งหมด

ความกว้างเป็นเศษส่วนพร้อมแถวโฟลว์

Row: รายการตรงกลางจะใช้ 0.7 เปอร์เซ็นต์ของความกว้าง Row ที่เหลืออยู่

ความกว้างเป็นเศษส่วนที่มีแถว

fillMaxColumnWidth() และ fillMaxRowHeight()

กำลังใช้ Modifier.fillMaxColumnWidth() หรือ Modifier.fillMaxRowHeight() ไปยังรายการใน FlowColumn หรือ FlowRow ตรวจสอบว่ารายการในคอลัมน์หรือแถวเดียวกันใช้ความกว้างหรือความสูงเท่ากับ รายการที่ใหญ่ที่สุดในคอลัมน์/แถว

เช่น ตัวอย่างนี้ใช้ FlowColumn เพื่อแสดงลิสต์ของ Android ของหวาน คุณจะเห็นความแตกต่างในความกว้างของสินค้าแต่ละรายการเมื่อ ระบบจะใช้ Modifier.fillMaxColumnWidth() กับรายการกับเมื่อไม่ใช้และ ห่อสินค้า

FlowColumn(
    Modifier
        .padding(20.dp)
        .fillMaxHeight()
        .fillMaxWidth(),
    horizontalArrangement = Arrangement.spacedBy(8.dp),
    verticalArrangement = Arrangement.spacedBy(8.dp),
    maxItemsInEachColumn = 5,
) {
    repeat(listDesserts.size) {
        Box(
            Modifier
                .fillMaxColumnWidth()
                .border(1.dp, Color.DarkGray, RoundedCornerShape(8.dp))
                .padding(8.dp)
        ) {

            Text(
                text = listDesserts[it],
                fontSize = 18.sp,
                modifier = Modifier.padding(3.dp)
            )
        }
    }
}

นำ Modifier.fillMaxColumnWidth() ไปใช้กับแต่ละรายการแล้ว

fillMaxColumnWidth

ไม่ได้ตั้งค่าการเปลี่ยนแปลงความกว้าง (ตัดรายการ)

ไม่มีการตั้งค่าความกว้างคอลัมน์สูงสุดของการเติมสี