Compose'da akış düzenleri

FlowRow ve FlowColumn, Row ve Column'a benzeyen ancak kapsayıcıda alan tükendiğinde öğelerin sonraki satıra geçmesi bakımından farklılık gösteren composable'lardır. Bu işlem birden fazla satır veya sütun oluşturur. Bir satırdaki öğe sayısı, maxItemsInEachRow veya maxItemsInEachColumn ayarlanarak da kontrol edilebilir. Duyarlı düzenler oluşturmak için genellikle FlowRow ve FlowColumn kullanabilirsiniz. Öğeler tek bir boyut için çok büyükse içerik kesilmez. Modifier.weight(weight) ile maxItemsInEach* kombinasyonunu kullanmak, gerektiğinde satır veya sütunun genişliğini dolduran/genişleyen düzenler oluşturmaya yardımcı olabilir.

Çip veya filtreleme kullanıcı arayüzü tipik bir örnektir:

Bir FlowRow'da daha fazla alan kalmadığında sonraki satıra taşan alanı gösteren 5 çip.
Şekil 1. FlowRow örneği

Temel kullanım

FlowRow veya FlowColumn kullanmak için bu composable'ları oluşturun ve standart akışı izlemesi gereken öğeleri içine yerleştirin:

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

Bu snippet, yukarıda gösterilen kullanıcı arayüzünü oluşturur. İlk satırda daha fazla alan kalmadığında öğeler otomatik olarak bir sonraki satıra aktarılır.

Akış düzeninin özellikleri

Akış düzenleri, uygulamanızda farklı düzenler oluşturmak için kullanabileceğiniz aşağıdaki özellik ve özelliklere sahiptir.

Ana eksen yerleşimi: yatay veya dikey düzenleme

Ana eksen, öğelerin yerleştirildiği eksendir (örneğin, FlowRow'da öğeler yatay olarak düzenlenir). FlowRow öğesindeki horizontalArrangement parametresi, öğeler arasında boş alanın nasıl dağıtılacağını kontrol eder.

Aşağıdaki tabloda FlowRow için öğelerde horizontalArrangement ayarıyla ilgili örnekler gösterilmektedir:

Yatay düzenleme FlowRow hücresinde ayarlandı

Sonuç

Arrangement.Start (Default)

Başlangıcı olan öğeler

Arrangement.SpaceBetween

Öğelerin aralarında boşluk bırakacak şekilde ayarlanması

Arrangement.Center

Ortada düzenlenen öğeler

Arrangement.End

Sona eklenen öğeler

Arrangement.SpaceAround

Çevrelerinde alan olacak şekilde düzenlenmiş öğeler

Arrangement.spacedBy(8.dp)

Belirli bir dp aralığındaki öğeler

Benzer seçenekler, FlowColumn için varsayılan olarak Arrangement.Top ile verticalArrangement ile kullanılabilir.

Çapraz eksen düzenlemesi

Çapraz eksen, ana eksenin tersi yönünde olan eksendir. Örneğin, FlowRow işlevinde bu dikey eksendir. Kapsayıcı içindeki genel içeriğin çapraz eksende düzenlenme şeklini değiştirmek için FlowRow için verticalArrangement ve FlowColumn için horizontalArrangement kullanın.

FlowRow için aşağıdaki tabloda, öğelerde farklı verticalArrangement ayarlama örnekleri gösterilmektedir:

Dikey düzenleme FlowRow tarihinde ayarlandı

Sonuç

Arrangement.Top (Default)

Kapsayıcı üst düzenlemesi

Arrangement.Bottom

Kapsayıcı alt düzenlemesi

Arrangement.Center

Konteyner merkezi düzenlemesi

FlowColumn için horizontalArrangement ile benzer seçenekler mevcut. Varsayılan çapraz eksen ayarlaması: Arrangement.Start.

Bağımsız öğe hizalaması

Satırdaki öğeleri farklı hizalamalarla tek tek yerleştirmek isteyebilirsiniz. Bu, mevcut satırdaki öğeleri hizaladığı için verticalArrangement ve horizontalArrangement satırlarından farklıdır. Bunu Modifier.align() ile uygulayabilirsiniz.

Örneğin, FlowRow içindeki öğeler farklı yüksekliklerde olduğunda, satır en büyük öğenin yüksekliğini alır ve öğelere Modifier.align(alignmentOption) uygular:

FlowRow için dikey hizalama ayarlandı

Sonuç

Alignment.Top (Default)

Üste hizalanan öğeler

Alignment.Bottom

Alta hizalanan öğeler

Alignment.CenterVertically

Ortaya hizalanan öğeler

FlowColumn için benzer seçenekler mevcut. Varsayılan hizalama Alignment.Start şeklindedir.

Satır veya sütundaki maksimum öğe sayısı

maxItemsInEachRow veya maxItemsInEachColumn parametreleri, ana eksende sonrakine sarmalanmadan önce bir satırda izin verilecek maksimum öğeleri tanımlar. Varsayılan değer, boyutları satıra sığmadığı sürece mümkün olduğunca çok sayıda öğeye izin veren Int.MAX_INT şeklindedir.

Örneğin, bir maxItemsInEachRow ayarlandığında başlangıç düzeni yalnızca 3 öğeye sahip olmaya zorlanır:

Maks. ayarlanmadı

maxItemsInEachRow = 3

Akış satırında maksimum ayarlanmadı Akış satırında maksimum öğe ayarlandı

Akış öğelerini geç yükleme

ContextualFlowRow ve ContextualFlowColumn, FlowRow ve FlowColumn'ın özel bir sürümüdür ve akış satırınızın veya sütununuzun içeriğini geç yüklemenize olanak tanır. Ayrıca, öğenin ilk satırda olup olmadığı gibi öğelerin konumuna (dizin, satır numarası ve kullanılabilir boyut) dair bilgiler de sağlar. Bu, büyük veri kümeleri için ve bir öğe hakkında bağlamsal bilgiye ihtiyacınız olduğunda yararlıdır.

maxLines parametresi, görüntülenen satır sayısını sınırlandırır. overflow parametresi ise öğeler taştığında nelerin görüntüleneceğini belirler. Böylece, özel bir expandIndicator veya collapseIndicator belirtebilirsiniz.

Örneğin, "+ (kalan öğe sayısı)" veya "Daha Az Göster" düğmesini göstermek için:

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

Bağlamsal akış satırları örneği.
Şekil 2. ContextualFlowRow örneği

Ürün ağırlıkları

Ağırlık, bir öğeyi faktörüne ve yerleştirildiği satırdaki kullanılabilir alana göre büyütür. Daha da önemlisi, bir öğenin genişliğini hesaplamak için ağırlıkların kullanılma şeklinde FlowRow ile Row arasında bir fark vardır. Rows için ağırlık, Row içindeki tüm öğeleri temel alır. FlowRow kullanıldığında ağırlık, FlowRow kapsayıcısındaki tüm öğeleri değil, bir öğenin yerleştirildiği satırdaki öğelere dayanır.

Örneğin, tamamı bir satırda yer alan ve her birinin farklı ağırlıkları 1f, 2f, 1f ve 3f olan 4 öğeniz varsa toplam ağırlık 7f olur. Bir satır veya sütunda kalan alan 7f değerine bölünür. Daha sonra her öğe genişliği şu kullanılarak hesaplanacaktır: weight * (remainingSpace / totalWeight).

Izgara benzeri bir düzen oluşturmak için Modifier.weight ve maksimum öğe sayısını FlowRow veya FlowColumn ile birlikte kullanabilirsiniz. Bu yaklaşım, cihazınızın boyutuna göre ayarlanan duyarlı düzenler oluşturmak için yararlıdır.

Ağırlıkları kullanarak yapabileceklerinize dair birkaç farklı örnek vardır. Aşağıda gösterildiği gibi, öğelerin eşit boyutlarda olduğu bir ızgara örneği verilmiştir:

Akış satırıyla oluşturulan ızgara
Şekil 3. Izgara oluşturmak için FlowRow kullanılıyor

Eşit öğe boyutlarında bir tablo oluşturmak için aşağıdakileri yapabilirsiniz:

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

Daha da önemlisi, başka bir öğe ekler ve 9 yerine 10 kez tekrarlarsanız tüm satırın toplam ağırlığı 1f olduğundan son öğe son sütunun tamamını kaplar:

Izgaradaki son öğe tam boyutta
Şekil 4. Son öğenin tam genişliği kapladığı bir ızgara oluşturmak için FlowRow kullanılıyor

Ağırlıkları Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio) veya Modifier.fillMaxWidth(fraction) gibi diğer Modifiers ile birleştirebilirsiniz. Bu değiştiricilerin tümü, FlowRow (veya FlowColumn) içindeki öğelerin duyarlı bir şekilde boyutlandırılması için birlikte çalışır.

Ayrıca, iki öğenin her biri genişliğin yarısını, bir öğenin ise sonraki sütunun tam genişliğini kapladığı, farklı öğe boyutlarında dönüşümlü bir tablo oluşturabilirsiniz:

Akış satırlı alternatif ızgara
Şekil 5. Satırların alternatif boyutlarına sahip FlowRow

Bu işlemi aşağıdaki kodla yapabilirsiniz:

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

Kesirli boyutlandırma

Modifier.fillMaxWidth(fraction) kullanarak, bir öğenin kullanması gereken kapsayıcının boyutunu belirtebilirsiniz. Bu, Modifier.fillMaxWidth(fraction) öğesinin Row veya Column öğesine uygulandığındakinden farklıdır. Row/Column öğe, tüm kapsayıcı genişliği yerine kalan genişliğin belirli bir yüzdesini kaplar.

Örneğin, aşağıdaki kod FlowRow ve Row kullanıldığında farklı sonuçlar verir:

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: Tüm kapsayıcı genişliğinin 0,7 kadarını içeren orta öğe.

Akış satırlı kesirli genişlik

Row: Ortadaki öğe, kalan Row genişliğinin %0,7'sini kapsıyor.

Satırlı kesirli genişlik

fillMaxColumnWidth() ve fillMaxRowHeight()

FlowColumn veya FlowRow içindeki bir öğeye Modifier.fillMaxColumnWidth() ya da Modifier.fillMaxRowHeight() uygulandığında, aynı sütun veya satırdaki öğeler, sütundaki/satırdaki en büyük öğeyle aynı genişliği veya yüksekliği alır.

Örneğin, bu örnekte Android tatlılarının listesini görüntülemek için FlowColumn kullanılmaktadır. Öğelere Modifier.fillMaxColumnWidth() uygulandığında ve öğelerin sarmalanmadığında her bir öğe genişliğindeki farkı görebilirsiniz.

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

Her öğeye Modifier.fillMaxColumnWidth() uygulandı

dolguMaksimumSütunGenişliği

Genişlik değişikliği ayarlanmadı (sarmalanan öğeler)

Dolgu maks. sütun genişliği ayarlanmadı