Compose'da akış düzenleri

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

Bunun tipik bir örneği, bir çip veya filtreleme kullanıcı arayüzü içindir:

FlowRow'da yer alan 5 çip yer alıyor.
Ş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 bu composable'ların 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 yer kalmadığında öğeler otomatik olarak sonraki satıra geçer.

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 düzenlemesi: yatay veya dikey düzenleme

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

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

Yatay düzenleme FlowRow için ayarlandı

Sonuç

Arrangement.Start (Default)

Başlangıca göre düzenlenen öğeler

Arrangement.SpaceBetween

Aralarında boşluk olan öğe düzenlemesi

Arrangement.Center

Ortada düzenlenmiş öğeler

Arrangement.End

Sonda düzenlenmiş öğeler

Arrangement.SpaceAround

Çevrelerindeki boşlukla sıralanmış öğeler

Arrangement.spacedBy(8.dp)

Belirli bir dp aralığıyla ayarlanan öğeler

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

Çapraz eksen düzenlemesi

Çapraz eksen, ana eksenin zıtsındaki eksendir. Örneğin, FlowRow için bu dikey eksendir. Kapsayıcı içindeki genel içeriğin çapraz eksende düzenlenme şeklini değiştirmek üzere FlowRow için verticalArrangement ve FlowColumn için horizontalArrangement kullanın.

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

FlowRow için dikey düzenleme ayarlandı

Sonuç

Arrangement.Top (Default)

Üstü kapsayıcı düzenlemesi

Arrangement.Bottom

Kapsayıcı alt düzenlemesi

Arrangement.Center

Container merkezi düzenlemesi

FlowColumn için horizontalArrangement ile benzer seçenekler mevcut. Varsayılan çapraz eksen düzenlemesi Arrangement.Start şeklindedir.

Bağımsız öğe hizalaması

Satır içindeki öğeleri farklı hizalamalara sahip tek tek konumlandırmak isteyebilirsiniz. Bu, geçerli satırdaki öğeleri hizaladığından verticalArrangement ve horizontalArrangement satırlarından farklıdır. Bunu Modifier.align() ile uygulayabilirsiniz.

Örneğin, bir FlowRow içindeki öğeler farklı yüksekliklerde olduğunda satır, en büyük öğenin yüksekliğini alır ve Modifier.align(alignmentOption) öğesini öğelere 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.

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

maxItemsInEachRow veya maxItemsInEachColumn parametreleri, ana eksende diğerine sarmalanmadan önce bir satıra izin verilecek maksimum öğe sayısını tanımlar. Varsayılan değer Int.MAX_INT şeklindedir. Bu seçenek, boyutları satıra sığmalarına izin verdiği sürece mümkün olduğunca fazla öğeye izin verir.

Örneğin, bir maxItemsInEachRow ayarlamak başlangıç düzenini yalnızca 3 öğeye sahip olmaya zorlar:

Ayarlanan maks. yok

maxItemsInEachRow = 3

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

Akış öğeleri geç yükleniyor

ContextualFlowRow ve ContextualFlowColumn, akış satırınızın veya sütununuzun içeriğini geç yüklemenize olanak tanıyan, FlowRow ve FlowColumn'un özel bir sürümüdür. Ayrıca, öğenin ilk satırda olup olmadığı gibi öğe konumu (dizin, satır numarası ve kullanılabilir boyut) hakkında da bilgiler sağlar. Bu, büyük veri kümeleri için ve bir öğe hakkında bağlamsal bilgiye 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, bir öğe sınırına ulaşıldığında neyin gösterilmesi gerektiğini belirler. Bu sayede ö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")
}

İçeriğe 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. Ağırlıkların bir öğenin genişliğini hesaplamak için nasıl kullanıldığı konusunda FlowRow ile Row arasında önemli bir fark vardır. Rows için ağırlık, Row içindeki tüm öğelere göre belirlenir. FlowRow ile ağırlık, FlowRow kapsayıcısındaki tüm öğeleri değil, bir öğenin yerleştirildiği satırdaki öğeleri temel alır.

Örneğin, bir satıra denk gelen ve her biri farklı ağırlıklara sahip 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 bir öğenin genişliği şu formülle hesaplanır: weight * (remainingSpace / totalWeight).

Izgara benzeri bir düzen oluşturmak için FlowRow veya FlowColumn ile Modifier.weight ve maksimum öğeleri birlikte kullanabilirsiniz. Bu yaklaşım, cihazınızın boyutuna uyum sağlayan duyarlı düzenler oluşturmak için yararlıdır.

Ağırlıkları kullanarak neler yapabileceğinize dair birkaç farklı örnek vardır. Bunlardan biri, aşağıda gösterildiği gibi öğelerin eşit büyüklükte olduğu bir ızgaradır:

Akış satırıyla ızgara oluşturuldu
Şekil 3. Tablo oluşturmak için FlowRow kullanma

Eşit boyutlardan oluşan 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)
    }
}

Önemli bir nokta da, başka bir öğe ekler ve bunu 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 öğe tüm genişliği kaplayan 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 öğeleri ile birleştirebilirsiniz. Bu değiştiricilerin tümü, FlowRow (veya FlowColumn) içindeki öğelerin duyarlı bir şekilde boyutlandırılmasına olanak tanımak için birlikte çalışır.

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

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

Bunun için aşağıdaki kodu kullanabilirsiniz:

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

Kısmi boyutlandırma

Modifier.fillMaxWidth(fraction) kullanarak bir öğenin kullanması gereken kapsayıcının boyutunu belirtebilirsiniz. Bu, Row veya Column öğesine uygulandığında Modifier.fillMaxWidth(fraction) özelliğinin çalışma şeklinden farklıdır. Row/Column öğe, tüm kapsayıcının 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 oranı olan orta öğe.

Akış satırlı kesirli genişlik

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

Satırlı kesirli genişlik

fillMaxColumnWidth() ve fillMaxRowHeight()

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

Örneğin, bu örnekte Android tatlıların listesini görüntülemek için FlowColumn kullanılmıştır. Öğelere Modifier.fillMaxColumnWidth() uygulandığında, öğelerin sarmalanmadığında ve uygulanmadığında her öğenin genişlikleri arasındaki 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ı

dolguMaksSütunGenişliği

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

Maksimum dolgu sütun genişliği ayarlanmadı