چیدمان‌های جاری در Compose

FlowRow و FlowColumn ترکیب‌پذیرهایی هستند که مشابه Row و Column هستند، اما تفاوتشان در این است که وقتی فضای محفظه تمام می‌شود، موارد به خط بعدی منتقل می‌شوند. این کار چندین ردیف یا ستون ایجاد می‌کند. تعداد موارد در یک خط را می‌توان با تنظیم maxItemsInEachRow یا maxItemsInEachColumn نیز کنترل کرد. اغلب می‌توانید از FlowRow و FlowColumn برای ساختن چیدمان‌های واکنش‌گرا استفاده کنید— اگر موارد برای یک بُعد خیلی بزرگ باشند، محتوا قطع نخواهد شد، و استفاده از ترکیبی از maxItemsInEach* با Modifier.weight(weight) می‌تواند به ساختن چیدمان‌هایی کمک کند که درصورت نیاز، عرض ردیف یا ستون را پر/گسترش می‌دهند.

نمونه معمول برای تراشه یا واسط کاربر فیلتر کردن است:

‫۵ تراشه در FlowRow که نشان می‌دهد وقتی فضای بیشتری دردسترس نیست، تراشه‌ها به خط بعدی سرریز می‌شوند.
شکل ۱. نمونه 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")
    }
}

این قطعه کد منجر به نمایش واسط کاربری بالا می‌شود، که در آن موارد به‌طور خودکار به ردیف بعدی منتقل می‌شوند وقتی که دیگر فضایی در ردیف اول وجود نداشته باشد.

ویژگی‌های چیدمان جاری

چیدمان‌های Flow ویژگی‌ها و مشخصه‌های زیر را دارند که می‌توانید از آن‌ها برای ایجاد چیدمان‌های مختلف در برنامه‌تان استفاده کنید.

آرایش محور اصلی: آرایش افقی یا عمودی

محور اصلی محوری است که موارد روی آن چیده می‌شوند (برای مثال، در 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 حداکثر موارد را در محور اصلی تعریف می‌کنند تا قبل‌از رفتن به خط بعدی، در یک خط قرار بگیرند. مقدار پیش‌فرض Int.MAX_INT است که تا جایی که اندازه موارد اجازه دهد، بیشترین تعداد ممکن را در خط قرار می‌دهد.

برای مثال، تنظیم maxItemsInEachRow باعث می‌شود چیدمان اولیه فقط ۳ مورد داشته باشد:

حداکثری تنظیم نشده است

maxItemsInEachRow = 3

حداکثری برای ردیف جریان تنظیم نشده است حداکثر موارد تنظیم‌شده در ردیف جریان

وزن‌های مورد

وزن، اندازه مورد را براساس ضریب آن و فضای دردسترس در خطی که در آن قرار گرفته است افزایش می‌دهد. نکته مهم این است که بین 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)
    }
}

نکته مهم اینکه اگر مورد دیگری اضافه کنید و آن را ۱۰ بار به‌جای ۹ بار تکرار کنید، مورد آخر کل ستون آخر را اشغال می‌کند، زیرا وزن کل برای کل ردیف 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: مورد میانی با ۰٫۷ کسر از کل عرض محفظه.

عرض کسری با ردیف جاری

‫Row: مورد میانی ۰٫۷ درصد از پهنای 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

تغییر عرضی تنظیم نشده است (موارد پیچیده شده)

حداکثر عرض ستون برای پر کردن تنظیم نشده است