Compose'da akış düzenleri

FlowRow ve FlowColumn, Row ve Column'e benzer ancak kapsayıcıda yer kalmadığında öğelerin bir sonraki satıra akması bakımından farklı olan kompozisyonlardır. Bu işlemle birden fazla satır veya sütun oluşturulur. Bir satırdaki öğe sayısı, maxItemsInEachRow veya maxItemsInEachColumn ayarlanarak da kontrol edilebilir. FlowRow ve FlowColumn'i kullanarak duyarlı düzenler oluşturabilirsiniz. Öğeler bir boyut için çok büyükse içerik kesilmez. maxItemsInEach* ile Modifier.weight(weight)'ı birlikte kullanarak gerektiğinde bir satırın veya sütunun genişliğini dolduran/genişleten düzenler oluşturabilirsiniz.

Tipik bir örnek, çip veya filtreleme kullanıcı arayüzüdür:

FlowRow'daki 5 çip, yer kalmadığında taşmayı sonraki satıra gösterir.
Şekil 1. FlowRow
örneği

Temel kullanım

FlowRow veya FlowColumn'ü kullanmak için aşağıdaki bileşenleri oluşturun ve içine standart akışı takip etmesi gereken öğeleri 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, ilk satırda yer kalmadığında öğelerin otomatik olarak bir sonraki satıra aktığı, yukarıda gösterilen kullanıcı arayüzünü oluşturur.

Akış düzeninin özellikleri

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

Ana eksen düzenlemesi: yatay veya dikey düzenleme

Ana eksen, öğelerin yerleştirildiği eksendir (örneğin, FlowRow öğeleri yatay olarak düzenlenir). FlowRow içindeki horizontalArrangement parametresi, boş alanın öğeler arasında dağıtılma şeklini kontrol eder.

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

Yatay düzenleme FlowRow olarak ayarlandı

Sonuç

Arrangement.Start (Default)

Başlangıçla düzenlenmiş öğeler

Arrangement.SpaceBetween

Öğeler arasında boşluk olacak şekilde düzenleme

Arrangement.Center

Öğeler ortada düzenlenir.

Arrangement.End

Sonuna yerleştirilen öğeler

Arrangement.SpaceAround

Etrafında boşluk bırakılarak düzenlenmiş öğeler

Arrangement.spacedBy(8.dp)

Belirli bir dp değerine göre aralıklı öğeler

FlowColumn için verticalArrangement ile benzer seçenekler kullanılabilir. Varsayılan değer Arrangement.Top'dir.

Çapraz eksen düzenlemesi

Çapraz eksen, ana eksene ters yönde olan eksendir. Örneğin, FlowRow için bu dikey eksendir. Kapsayıcıdaki genel içeriğin çapraz eksende nasıl düzenleneceğini 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 olarak ayarlandı

Sonuç

Arrangement.Top (Default)

Kapsayıcı üst düzenlemesi

Arrangement.Bottom

Kapsayıcı alt düzenlemesi

Arrangement.Center

Kapsayıcı merkezi düzenlemesi

FlowColumn için horizontalArrangement ile benzer seçenekler kullanılabilir. Varsayılan çapraz eksen düzenlemesi Arrangement.Start'tür.

Öğeleri tek tek hizalama

Satırdaki öğeleri farklı hizalamalarla konumlandırmak isteyebilirsiniz. Bu düğme, öğeleri mevcut satır içinde hizalladığından verticalArrangement ve horizontalArrangement'ten farklıdır. Bunu Modifier.align() ile uygulayabilirsiniz.

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

Dikey hizalama FlowRow olarak ayarlandı

Sonuç

Alignment.Top (Default)

Öğeler üst tarafa hizalandı

Alignment.Bottom

Öğeler alta hizalandı

Alignment.CenterVertically

Öğeler ortaya hizalanır.

FlowColumn için benzer seçenekler mevcuttur. Varsayılan hizalama Alignment.Start'tür.

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

maxItemsInEachRow veya maxItemsInEachColumn parametreleri, bir satırda izin verilecek maksimum öğeyi tanımlar ve ardından bir sonraki satıra sarmalanır. Varsayılan değer Int.MAX_INT'tür. Bu değer, boyutları satıra sığmasına izin verdiği sürece mümkün olduğunca fazla öğeye izin verir.

Örneğin, maxItemsInEachRow ayarlandığında ilk düzenin yalnızca 3 öğe içermesi zorunlu kılınabilir:

Maksimum değer ayarlanmadı

maxItemsInEachRow = 3

Akış satırında maksimum değer ayarlanmadı Akış satırında ayarlanan maksimum öğe sayısı

Akış öğelerini geç yükleme

ContextualFlowRow ve ContextualFlowColumn, akış satırınızın veya sütununuzun içeriğini yavaşça yüklemenize olanak tanıyan FlowRow ve FlowColumn'in özelleştirilmiş bir sürümüdür. Ayrıca, öğenin ilk satırda olup olmadığı gibi öğelerin konumu (dizin, satır numarası ve kullanılabilir boyut) hakkında bilgi sağlarlar. Bu, büyük veri kümeleri için ve bir öğeyle ilgili bağlamsal bilgilere ihtiyacınız olduğunda faydalıdır.

maxLines parametresi, görüntülenen satır sayısını sınırlar ve overflow parametresi, öğelerin taştığı durumlarda neyin gösterileceğini belirtir. Böylece özel bir expandIndicator veya collapseIndicator belirtebilirsiniz.

Örneğin, "+ (kalan öğe sayısı)" veya "Daha Az Göster" düğmesi 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ğlama dayalı akış satırları örneği.
Şekil 2. ContextualFlowRow
örneği

Öğe ağırlıkları

Ağırlık, bir öğenin faktörüne ve yerleştirildiği satırdaki kullanılabilir alana göre öğeyi büyütür. Önemli bir nokta, bir öğenin genişliğini hesaplamak için ağırlıkların nasıl kullanıldığıyla ilgili olarak FlowRow ve Row arasında bir fark olmasıdır. Rows için ağırlık, Row'daki tüm öğelere dayanır. FlowRow ile ağırlık, FlowRow kapsayıcısındaki tüm öğelere değil, bir öğenin yerleştirildiği satırdaki öğelere dayanır.

Örneğin, aynı satıra ait 4 öğeniz varsa ve bunların her biri 1f, 2f, 1f ve 3f ağırlıklarına sahipse toplam ağırlık 7f olur. Bir satır veya sütundaki kalan alan 7f'e bölünür. Ardından her öğe genişliği şu şekilde hesaplanır: weight * (remainingSpace / totalWeight).

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

Ağırlıkları kullanarak neler başarabileceğinize dair birkaç farklı örnek vardır. Aşağıda gösterildiği gibi öğelerin eşit boyutta olduğu bir ızgara buna örnek gösterilebilir:

Akış satırı ile oluşturulan ızgara
Şekil 3. FlowRow ile ızgara oluşturma

Eşit öğe boyutlarına sahip bir ızgara oluşturmak için şunları 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)
    }
}

Önemli bir nokta, başka bir öğe ekleyip bunu 9 yerine 10 kez tekrarlarsanız tüm satırın toplam ağırlığı 1f olduğu için son öğe son sütunun tamamını kaplar:

Tabloda son öğe tam boyutta
Şekil 4. Son öğenin tüm genişliği kapladığı bir ızgara oluşturmak için FlowRow kullanma

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ı boyutlandırılmasına olanak tanımak için birlikte çalışır.

Ayrıca, iki öğenin her birinin genişliğin yarısını, bir öğenin ise sonraki sütunun tüm genişliğini kapladığı, farklı öğe boyutlarından oluşan bir ızgara da oluşturabilirsiniz:

Akış satırı içeren alternatif ızgara
Şekil 5. FlowRow satır boyutları değişken

Bunu 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) özelliğini kullanarak bir öğenin kaplaması gereken kapsayıcının boyutunu belirtebilirsiniz. Bu, Modifier.fillMaxWidth(fraction)'ün Row veya Column'ye uygulandığındaki işleyişinden farklıdır. Row/Column öğeleri, kapsayıcının tüm genişliği yerine kalan genişliğin bir yüzdesini kaplar.

Örneğin, aşağıdaki kod FlowRow yerine 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'si kadar genişliğe sahip orta öğe.

Akış satırı içeren kesirli genişlik

Row: Ortadaki öğe, kalan Row genişliğinin yüzde 0,7'sini kaplıyor.

Satırla kesirli genişlik

fillMaxColumnWidth() ve fillMaxRowHeight()

FlowColumn veya FlowRow içindeki bir öğeye Modifier.fillMaxColumnWidth() ya da Modifier.fillMaxRowHeight() uygulamak, aynı sütundaki veya satırdaki öğelerin sütundaki/satırdaki en büyük öğeyle aynı genişliği veya yüksekliği kaplamasını sağlar.

Ö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 uygulanmadığında ve öğeler kaydırıldığında her öğenin 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 uygulanan Modifier.fillMaxColumnWidth()

fillMaxColumnWidth

Genişlik değişikliği ayarlanmadı (öğeleri sarmalama)

Doldurulacak maksimum sütun genişliği ayarlanmadı