تنسيقات التدفق في "إنشاء"

FlowRow وFlowColumn هما عنصران قابلان للتجميع يشبهان Row وColumn، ولكنهما يختلفان في أنّ العناصر تتدفق إلى السطر التالي عندما تنفد المساحة في الحاوية. يؤدي هذا إلى إنشاء صفوف أو أعمدة متعددة. يمكن أيضًا التحكّم في عدد العناصر في السطر من خلال ضبط maxItemsInEachRow أو maxItemsInEachColumn. يمكنك غالبًا استخدام FlowRow وFlowColumn لإنشاء تصاميم متجاوبة، ولن يتم اقتطاع المحتوى إذا كانت العناصر كبيرة جدًا لبُعد واحد، ويمكن أن يساعد استخدام maxItemsInEach* معModifier.weight(weight) في إنشاء تصاميم تُملأ/تُوسّع عرض صف أو عمود عند الحاجة.

يتمثل المثال المعتاد في شريحة أو واجهة مستخدم للفلترة:

5 شرائح في FlowRow، تعرض الفائض إلى السطر التالي عندما لا تتوفّر
مساحة إضافية
الشكل 1. مثال على 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، يتم ترتيب العناصر أفقيًا). تتحكّم المَعلمة horizontalArrangement في FlowRow في طريقة توزيع المساحة الفارغة بين العناصر.

يعرض الجدول التالي أمثلة على ضبط horizontalArrangement في العناصر للسمة FlowRow:

تم ضبط الترتيب الأفقي في FlowRow.

النتيجة

Arrangement.Start (Default)

العناصر المرتبطة ببداية

Arrangement.SpaceBetween

ترتيب العناصر مع ترك مسافة بينها

Arrangement.Center

العناصر مرتبة في الوسط

Arrangement.End

العناصر مرتبة في النهاية

Arrangement.SpaceAround

عناصر مرتبة مع مسافة حولها

Arrangement.spacedBy(8.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 إلى فرض تضمين 3 عناصر فقط في التنسيق الأولي، وهي:

لم يتم ضبط حدّ أقصى.

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

مثال على صفوف مسارات المستخدمين السياقية
الشكل 2. مثال على ContextualFlowRow

أوزان السلع

يزداد الوزن أي عنصر بناءً على عامله والمساحة المتاحة على الخط الذي تم وضعه فيه. من المهم معرفة أنّ هناك فرقًا بين FlowRow وRow في كيفية استخدام الأوزان لحساب عرض السلعة. بالنسبة إلى Rows، يستند الوزن إلى كل العناصر في Row. في سمة FlowRow، يستند الوزن إلى العناصر في الصف الذي يتم وضع العنصر فيه، وليس إلى جميع العناصر في حاوية FlowRow.

على سبيل المثال، إذا كان لديك 4 سلع تقع جميعها على خط واحد، ولكل منها كثافة مختلفة تبلغ 1f, 2f, 1f و3f، يكون إجمالي الكثافة 7f. سيتم تقسيم المساحة المتبقية في صف أو عمود على 7f. بعد ذلك، سيتم حساب عرض كل عنصر باستخدام: weight * (remainingSpace / totalWeight).

يمكنك استخدام مجموعة من Modifier.weight وعدد العناصر الأقصى مع FlowRow أو FlowColumn لإنشاء تنسيق شبيه بالشبكة. يعد هذا الأسلوب مفيدًا لإنشاء تخطيطات سريعة استجابة تتكيّف مع حجم جهازك.

في ما يلي بعض الأمثلة المختلفة على ما يمكنك تحقيقه باستخدام الأوزان. أحد الأمثلة على ذلك هو شبكة تكون فيها العناصر بنفس الحجم، كما هو موضح أدناه:

شبكة تم إنشاؤها باستخدام صف تدفق
الشكل 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) استجابةً للشاشة.

يمكنك أيضًا إنشاء شبكة بديلة لأحجام عناصر مختلفة، حيث يشغل عنصران نصف عرض كل منهما، ويشغل عنصر واحد عرض العمود التالي بالكامل:

شبكة بديلة مع صفّ تدفق
الشكل 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

لم يتم ضبط تغييرات العرض (التفاف العناصر)

لم يتم ضبط الحد الأقصى لعرض العمود المعبّأ