Compose में फ़्लो लेआउट

FlowRow और FlowColumn, Row और Column जैसे कॉम्पोज़ेबल हैं. हालांकि, इनमें अंतर यह है कि कंटेनर में जगह खत्म होने पर आइटम अगली लाइन में चले जाते हैं. इससे कई पंक्तियां या कॉलम बन जाते हैं. maxItemsInEachRow या maxItemsInEachColumn सेट करके भी, किसी लाइन में मौजूद आइटम की संख्या को कंट्रोल किया जा सकता है. रिस्पॉन्सिव लेआउट बनाने के लिए, अक्सर FlowRow और FlowColumn का इस्तेमाल किया जा सकता है. अगर किसी डाइमेंशन के लिए आइटम बहुत बड़े हैं, तो कॉन्टेंट काट नहीं जाएगा. साथ ही, maxItemsInEach* और Modifier.weight(weight) के कॉम्बिनेशन का इस्तेमाल करके, ऐसे लेआउट बनाए जा सकते हैं जो ज़रूरत पड़ने पर किसी पंक्ति या कॉलम की चौड़ाई को भर/बढ़ा सकते हैं.

चिप या फ़िल्टर करने वाले यूज़र इंटरफ़ेस (यूआई) का सामान्य उदाहरण:

FlowRow में पांच चिप, जिनमें अगली लाइन में ओवरफ़्लो दिख रहा है, क्योंकि वहां कोई जगह उपलब्ध नहीं है.
पहला डायग्राम. FlowRow का उदाहरण

बुनियादी इस्तेमाल

FlowRow या FlowColumn का इस्तेमाल करने के लिए, ये कॉम्पोनेंट बनाएं और उनमें ऐसे आइटम डालें जो स्टैंडर्ड फ़्लो का पालन करते हों:

@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")
    }
}

इस स्निपेट से ऊपर दिखाया गया यूज़र इंटरफ़ेस (यूआई) बनता है. इसमें पहली पंक्ति में जगह न होने पर, आइटम अपने-आप अगली पंक्ति में चले जाते हैं.

फ़्लो लेआउट की सुविधाएं

फ़्लो लेआउट में ये सुविधाएं और प्रॉपर्टी होती हैं. इनका इस्तेमाल करके, अपने ऐप्लिकेशन में अलग-अलग लेआउट बनाए जा सकते हैं.

मुख्य अक्ष का क्रम: हॉरिज़ॉन्टल या वर्टिकल क्रम

मुख्य ऐक्सिस वह ऐक्सिस होता है जिस पर आइटम दिखाए जाते हैं. उदाहरण के लिए, FlowRow में आइटम हॉरिज़ॉन्टल तरीके से व्यवस्थित किए जाते हैं. FlowRow में मौजूद horizontalArrangement पैरामीटर, आइटम के बीच खाली जगह के बंटवारे के तरीके को कंट्रोल करता है.

यहां दी गई टेबल में, FlowRow के लिए आइटम पर horizontalArrangement सेट करने के उदाहरण दिए गए हैं:

हॉरिज़ॉन्टल क्रम, FlowRow पर सेट किया गया

नतीजा

Arrangement.Start (Default)

शुरू होने के समय के हिसाब से व्यवस्थित किए गए आइटम

Arrangement.SpaceBetween

आइटम के बीच स्पेस के साथ व्यवस्थित करना

Arrangement.Center

बीच में व्यवस्थित किए गए आइटम

Arrangement.End

आइटम आखिर में व्यवस्थित किए गए

Arrangement.SpaceAround

आइटम के बीच में जगह छोड़कर व्यवस्थित करना

Arrangement.spacedBy(8.dp)

आइटम के बीच में कुछ खास डीपी का स्पेस होना

FlowColumn के लिए, verticalArrangement में मिलते-जुलते विकल्प उपलब्ध हैं. इनमें Arrangement.Top डिफ़ॉल्ट तौर पर सेट होता है.

क्रॉस ऐक्सिस का क्रम

क्रॉस ऐक्सिस, मुख्य ऐक्सिस के विपरीत दिशा में मौजूद ऐक्सिस होता है. उदाहरण के लिए, FlowRow में यह वर्टिकल ऐक्सिस है. कंटेनर में मौजूद सभी कॉन्टेंट को क्रॉस ऐक्सिस में व्यवस्थित करने का तरीका बदलने के लिए, FlowRow के लिए verticalArrangement और FlowColumn के लिए horizontalArrangement का इस्तेमाल करें.

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, मुख्य ऐक्सिस में मौजूद आइटम की संख्या तय करते हैं, ताकि अगली लाइन में जाने से पहले एक लाइन में आइटम दिखाए जा सकें. डिफ़ॉल्ट वैल्यू Int.MAX_INT है. इसमें ज़्यादा से ज़्यादा आइटम जोड़े जा सकते हैं. हालांकि, इसके लिए ज़रूरी है कि आइटम का साइज़, लाइन में फ़िट हो.

उदाहरण के लिए, maxItemsInEachRow सेट करने पर, शुरुआती लेआउट में सिर्फ़ तीन आइटम दिखते हैं:

कोई मैक्स सेट नहीं है

maxItemsInEachRow = 3

फ़्लो लाइन में कोई मैक्सिमम वैल्यू सेट नहीं है फ़्लो लाइन पर सेट किए गए आइटम की ज़्यादा से ज़्यादा संख्या

फ़्लो आइटम को लेज़ी लोड करना

ContextualFlowRow और ContextualFlowColumn, FlowRow और FlowColumn के खास वर्शन हैं. इनकी मदद से, फ़्लो की पंक्ति या कॉलम के कॉन्टेंट को धीरे-धीरे लोड किया जा सकता है. ये आइटम की पोज़िशन (इंडेक्स, पंक्ति की संख्या, और उपलब्ध साइज़) के बारे में भी जानकारी देते हैं. जैसे, आइटम पहली पंक्ति में है या नहीं. यह बड़े डेटा-सेट के लिए फ़ायदेमंद है. साथ ही, अगर आपको किसी आइटम के बारे में कॉन्टेक्स्ट के हिसाब से जानकारी चाहिए, तो भी यह फ़ायदेमंद है.

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")
}

कॉन्टेक्स्ट फ़्लो की लाइनों का उदाहरण.
दूसरी इमेज. ContextualFlowRow का उदाहरण

सामान का वज़न

किसी आइटम का वज़न, उसके फ़ैक्टर और उस लाइन में मौजूद जगह के आधार पर तय होता है जिसमें उसे रखा गया है. अहम बात यह है कि FlowRow और Row के बीच अंतर है. इस अंतर से पता चलता है कि किसी आइटम की चौड़ाई का हिसाब लगाने के लिए, वज़न का इस्तेमाल कैसे किया जाता है. Rows के लिए, वज़न Row में मौजूद सभी आइटम पर आधारित होता है. FlowRow के लिए, वज़न उस लाइन में मौजूद आइटम पर आधारित होता है जिसमें आइटम रखा गया है, न कि FlowRow कंटेनर में मौजूद सभी आइटम पर.

उदाहरण के लिए, अगर आपके पास चार आइटम हैं, जो एक ही लाइन में हैं और जिनका वज़न 1f, 2f, 1f और 3f है, तो कुल वज़न 7f होगा. किसी पंक्ति या कॉलम में बचे हुए स्पेस को 7f से भाग दिया जाएगा. इसके बाद, हर आइटम की चौड़ाई का हिसाब, weight * (remainingSpace / totalWeight) का इस्तेमाल करके लगाया जाएगा.

ग्रिड जैसा लेआउट बनाने के लिए, Modifier.weight और ज़्यादा आइटम के साथ FlowRow या FlowColumn का इस्तेमाल किया जा सकता है. यह तरीका, आपके डिवाइस के साइज़ के हिसाब से अडजस्ट होने वाले रिस्पॉन्सिव लेआउट बनाने के लिए मददगार है.

यहां कुछ उदाहरण दिए गए हैं, जिनसे पता चलता है कि वेट का इस्तेमाल करके क्या-क्या किया जा सकता है. उदाहरण के लिए, ऐसा ग्रिड जिसमें सभी आइटम का साइज़ एक जैसा हो, जैसा कि यहां दिखाया गया है:

फ़्लो लाइन की मदद से बनाया गया ग्रिड
तीसरी इमेज. ग्रिड बनाने के लिए 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 बार दोहराया जाता है, तो आखिरी आइटम पूरे आखिरी कॉलम को ले लेता है, क्योंकि पूरी पंक्ति का कुल वज़न 1f होता है:

ग्रिड पर आखिरी आइटम का पूरा साइज़
चौथी इमेज. FlowRow का इस्तेमाल करके, आखिरी आइटम को पूरी चौड़ाई में दिखाने वाला ग्रिड बनाना

वैल्यू को अन्य Modifiers के साथ जोड़ा जा सकता है, जैसे कि Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio) या Modifier.fillMaxWidth(fraction). ये सभी मॉडिफ़ायर एक साथ काम करते हैं, ताकि FlowRow (या FlowColumn) में मौजूद आइटम का साइज़, डिवाइस के हिसाब से बदल सके.

अलग-अलग साइज़ के आइटम के लिए, वैकल्पिक ग्रिड भी बनाया जा सकता है. इसमें दो आइटम, कॉलम की आधी चौड़ाई लेते हैं और एक आइटम, अगले कॉलम की पूरी चौड़ाई लेता है:

फ़्लो लाइन के साथ ग्रिड को वैकल्पिक तौर पर दिखाना
पांचवीं इमेज. 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: बीच में मौजूद आइटम, बाकी Row चौड़ाई का 0.7 प्रतिशत ले रहा है.

पंक्ति के साथ फ़्रैक्शनल चौड़ाई

fillMaxColumnWidth() और fillMaxRowHeight()

FlowColumn या FlowRow में मौजूद किसी आइटम पर Modifier.fillMaxColumnWidth() या Modifier.fillMaxRowHeight() लागू करने से यह पक्का होता है कि एक ही कॉलम या पंक्ति में मौजूद आइटम, कॉलम/पंक्ति के सबसे बड़े आइटम के बराबर चौड़ाई या ऊंचाई वाले हों.

उदाहरण के लिए, इस उदाहरण में Android डिवाइसों के डिसर्ट की सूची दिखाने के लिए, FlowColumn का इस्तेमाल किया गया है. जब आइटम पर 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

चौड़ाई में कोई बदलाव नहीं किया गया (आइटम को रैप करना)

कॉलम की चौड़ाई की कोई सीमा सेट नहीं है