Listeler ve ızgaralar

Birçok uygulamanın öğe koleksiyonları göstermesi gerekir. Bu dokümanda, bunu Jetpack Compose'da nasıl verimli bir şekilde yapabileceğiniz açıklanmaktadır.

Kullanım alanınızın herhangi bir kaydırma gerektirmediğini biliyorsanız, basit bir Column veya Row kullanın (yöne bağlı olarak) ve her bir öğenin içeriğini yineleme şu şekilde yapılır:

@Composable
fun MessageList(messages: List<Message>) {
    Column {
        messages.forEach { message ->
            MessageRow(message)
        }
    }
}

verticalScroll() değiştiricisini kullanarak Column'u kaydırılabilir hale getirebiliriz.

Tembel listeler

Çok sayıda öğe (veya uzunluğu bilinmeyen bir liste) görüntülemeniz gerekiyorsa Column gibi bir düzen kullanmak, tüm öğeler oluşturulacağı ve görünür olup olmadıklarına göre düzenleneceği için performans sorunlarına neden olabilir.

Oluşturma, yalnızca bileşenin görüntü alanında görünen öğeleri oluşturan ve düzenleyen bir bileşen grubu sağlar. Bu bileşenler şunları içerir: LazyColumn ve LazyRow.

Adından da anlaşılacağı gibi, LazyColumn ile LazyRow arasındaki fark, öğelerin düzenlenme ve kaydırma yönüdür. LazyColumn dikey kaydırmalı bir liste, LazyRow ise yatay kaydırmalı bir liste oluşturur.

Tembel bileşenler, Compose'daki çoğu düzenden farklıdır. Şunun yerine: bir @Composable içerik engelleme parametresini kabul ederek, uygulamaların composable'lar yayınlarken, Tembel bileşenler bir LazyListScope.() blok sağlar. Bu LazyListScope blok, uygulamaların öğe içeriğini açıklamasına olanak tanıyan bir DSL sunar. Ardından, tembel bileşen her öğenin içeriğini düzen ve kaydırma konumu tarafından gerektiği şekilde eklemekten sorumludur.

LazyListScope DSL

LazyListScope DSL'si, öğeleri açıklamak için çeşitli işlevler sağlar tıklayın. En basit haliyle, item() tek bir öğe, items(Int) ise birden fazla öğe ekler:

LazyColumn {
    // Add a single item
    item {
        Text(text = "First item")
    }

    // Add 5 items
    items(5) { index ->
        Text(text = "Item: $index")
    }

    // Add another single item
    item {
        Text(text = "Last item")
    }
}

List gibi öğe koleksiyonları eklemenize olanak tanıyan çeşitli uzantı işlevleri de vardır. Bu uzantılar, reklamımızı yukarıdaki Column örneğimizi taşıyın:

/**
 * import androidx.compose.foundation.lazy.items
 */
LazyColumn {
    items(messages) { message ->
        MessageRow(message)
    }
}

items() uzantı işlevinin itemsIndexed() adlı bir varyantı da vardır. Bu varyant, dizini sağlar. Daha fazla bilgi için lütfen LazyListScope referansına bakın.

Yavaş ızgaralar

LazyVerticalGrid ve LazyHorizontalGrid bileşenleri, öğeleri ızgarada görüntüleme desteği sağlar. Yavaş dikey ızgaralar öğelerini birden fazla sütuna yayılmış, dikey olarak kaydırılabilir bir kapsayıcıda gösterir. Yavaş yatay ızgaralar ise yatay eksende aynı davranışı gösterir.

Tablolar, listelerle aynı güçlü API özelliklerine sahiptir ve içeriği açıklamak için çok benzer bir DSL'yi (LazyGridScope.()) kullanır.

Fotoğraf ızgarasının gösterildiği bir telefonun ekran görüntüsü

Şuradaki columns parametresi: LazyVerticalGrid ve rows parametresini dahil edin: LazyHorizontalGrid hücrelerin sütun veya satırlara nasıl ayrılacağını kontrol edebilirsiniz. Aşağıdaki örnekte, her sütunu en az 128.dp genişliğinde ayarlamak için GridCells.Adaptive kullanılarak öğeler ızgara şeklinde gösterilmektedir:

LazyVerticalGrid(
    columns = GridCells.Adaptive(minSize = 128.dp)
) {
    items(photos) { photo ->
        PhotoItem(photo)
    }
}

LazyVerticalGrid, öğeler için bir genişlik belirtmenize olanak tanır. Ardından ızgara, mümkün olduğunca çok sütuna sığdırılır. Kalan genişlik, sütun sayısı hesaplandıktan sonra sütunlar arasında eşit olarak dağıtılır. Bu uyarlanabilir boyutlandırma yöntemi, özellikle farklı ekran boyutlarında öğe grupları görüntülemek için yararlıdır.

Kullanılacak sütun sayısını tam olarak biliyorsanız bunun yerine gerekli sütun sayısını içeren bir GridCells.Fixed örneği sağlayabilirsiniz.

Tasarımınızda yalnızca belirli öğelerin standart dışı boyutlara sahip olması gerekiyorsa öğeler için özel sütun aralıkları sağlamak üzere ızgara desteğini kullanabilirsiniz. Sütun aralığınıspan LazyGridScope DSL item ve items yöntemleri. maxLineSpan, span kapsamının değerlerinden biri, özellikle uyarlanabilir boyutlandırma, çünkü sütun sayısı sabit değildir. Bu örnekte, tam satır kapsamının nasıl sağlanacağı gösterilmektedir:

LazyVerticalGrid(
    columns = GridCells.Adaptive(minSize = 30.dp)
) {
    item(span = {
        // LazyGridItemSpanScope:
        // maxLineSpan
        GridItemSpan(maxLineSpan)
    }) {
        CategoryCard("Fruits")
    }
    // ...
}

Eğik ızgara

LazyVerticalStaggeredGrid ve LazyHorizontalStaggeredGrid geç yüklenen, aşamalı bir öğe ızgarası oluşturmanızı sağlayan composable'lardır. Yavaş dikey kademeli ızgara, öğelerini birden fazla sütuna yayılan ve öğelerin farklı yüksekliklere sahip olmasına olanak tanıyan dikey olarak kaydırılabilir bir kapsayıcıda gösterir. Tembel yatay ızgaralar, tablodaki öğe içeren yatay eksen.

Aşağıdaki snippet, öğe başına 200.dp genişliğinde LazyVerticalStaggeredGrid kullanmanın temel bir örneğidir:

LazyVerticalStaggeredGrid(
    columns = StaggeredGridCells.Adaptive(200.dp),
    verticalItemSpacing = 4.dp,
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    content = {
        items(randomSizedPhotos) { photo ->
            AsyncImage(
                model = photo,
                contentScale = ContentScale.Crop,
                contentDescription = null,
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
            )
        }
    },
    modifier = Modifier.fillMaxSize()
)

Şekil 1. Eğik kademeli dikey ızgara örneği

Sabit bir sütun sayısı ayarlamak için StaggeredGridCells.Adaptive yerine StaggeredGridCells.Fixed(columns) kullanabilirsiniz. Bu işlem, kullanılabilir genişliği sütun sayısına (veya yatay ızgara için satır sayısına) böler ve her öğenin bu genişliği (veya yatay ızgara için yüksekliği) kaplamasını sağlar:

LazyVerticalStaggeredGrid(
    columns = StaggeredGridCells.Fixed(3),
    verticalItemSpacing = 4.dp,
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    content = {
        items(randomSizedPhotos) { photo ->
            AsyncImage(
                model = photo,
                contentScale = ContentScale.Crop,
                contentDescription = null,
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
            )
        }
    },
    modifier = Modifier.fillMaxSize()
)
Compose&#39;da kademeli resim ızgarası
Şekil 2. Sabit sütunlara sahip, eğik aralıklı dikey ızgara örneği

İçerik dolgusu

Bazen içeriğin kenarlarına dolgu eklemeniz gerekir. Tembel bileşenlerden yararlanarak, PaddingValues desteklemesi için contentPadding parametresine eklemeniz gerekir:

LazyColumn(
    contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
) {
    // ...
}

Bu örnekte, yatay kenarlara (sol ve alt kenarlara) 16.dp oranında dolgu ekliyoruz. sağda), ardından içeriğin üst ve alt kısmına 8.dp tuşlarına basın.

Bu dolgunun LazyColumn kendisi. Yukarıdaki örnekte, ilk öğe üst kısmına 8.dp dolgu, son öğe alt kısmına 8.dp dolgu, tüm öğeler ise sol ve sağ tarafına 16.dp dolgu ekler.

İçerik aralığı

Öğeler arasına boşluk eklemek için Arrangement.spacedBy() simgesini kullanabilirsiniz. Aşağıdaki örnekte her öğe arasına 4.dp boşluk eklenmiştir:

LazyColumn(
    verticalArrangement = Arrangement.spacedBy(4.dp),
) {
    // ...
}

LazyRow için de benzer şekilde:

LazyRow(
    horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
    // ...
}

Ancak ızgaralar hem dikey hem de yatay düzenlemeleri kabul eder:

LazyVerticalGrid(
    columns = GridCells.Fixed(2),
    verticalArrangement = Arrangement.spacedBy(16.dp),
    horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
    items(photos) { item ->
        PhotoItem(item)
    }
}

Öğe anahtarları

Varsayılan olarak her öğenin durumu, öğenin listedeki veya tablodaki konumuna göre anahtarlanır. Ancak, konumu değişen öğeler hatırlanan durumu etkili bir şekilde kaybettiği için veri kümesi değişirse bu durum sorunlara neden olabilir. Tahmin edebileceğiniz gibi LazyColumn içindeki LazyRow senaryosunda satır, öğe konumunu değiştirirse bunun ardından kullanıcı, satırdaki kaydırma konumunu kaybeder.

Bununla mücadele etmek amacıyla, her öğe için sabit ve benzersiz bir anahtar sağlayarak key parametresi için bir blok. Sabit bir anahtar sağlamak, öğe durumunun ve veri kümesi değişiklikleri arasında tutarlılık sağlar:

LazyColumn {
    items(
        items = messages,
        key = { message ->
            // Return a stable + unique key for the item
            message.id
        }
    ) { message ->
        MessageRow(message)
    }
}

Anahtarları sağlayarak, Compose'un yeniden sıralamaları doğru şekilde işlemesine yardımcı olursunuz. Örneğin, öğeniz hatırlanan durum içeriyorsa ayar anahtarları, konumu değiştiğinde Oluştur'un bu durumu öğeyle birlikte taşımasına olanak tanır.

LazyColumn {
    items(books, key = { it.id }) {
        val rememberedValue = remember {
            Random.nextInt()
        }
    }
}

Ancak öğe anahtarı olarak kullanabileceğiniz türlerle ilgili bir sınırlama vardır. Anahtarın türü şu tarafından desteklenmelidir: Bundle, Android’in etkinlik yeniden oluşturulduğunda geçerli olur. Bundle, temel öğeler, emin olun.

LazyColumn {
    items(books, key = {
        // primitives, enums, Parcelable, etc.
    }) {
        // ...
    }
}

Anahtar, Bundle tarafından desteklenmelidir. Böylece, etkinlik yeniden oluşturulduğunda veya bu öğeden uzaklaşıp geri geldiğinizde bile, öğe bileşiğinin içindeki rememberSaveable geri yüklenebilir.

LazyColumn {
    items(books, key = { it.id }) {
        val rememberedValue = rememberSaveable {
            Random.nextInt()
        }
    }
}

Öğe animasyonları

RecyclerView widget'ını kullandıysanız öğe değişikliklerini otomatik olarak animasyonlu hale getirdiğini bilirsiniz. Tembel düzenler, öğelerin yeniden sıralanması için aynı işlevi sağlar. API basittir; tek yapmanız gereken animateItemPlacement değiştiricisi:

LazyColumn {
    // It is important to provide a key to each item to ensure animateItem() works as expected.
    items(books, key = { it.id }) {
        Row(Modifier.animateItem()) {
            // ...
        }
    }
}

Gerekirse özel animasyon spesifikasyonu da sağlayabilirsiniz:

LazyColumn {
    items(books, key = { it.id }) {
        Row(
            Modifier.animateItem(
                fadeInSpec = tween(durationMillis = 250),
                fadeOutSpec = tween(durationMillis = 100),
                placementSpec = spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)
            )
        ) {
            // ...
        }
    }
}

Taşınan öğenin yeni konumunu bulmak için öğeleriniz için anahtar sağladığınızdan emin olun.

Yapışkan üstbilgiler (deneysel)

"Yapışkan başlık" kalıbı, gruplandırılmış verilerin listelerini görüntülerken kullanışlıdır. Aşağıda, her kişinin baş harfine göre gruplandırılmış bir "kişiler listesi" örneğini görebilirsiniz:

Bir telefonda kişiler listesinde yukarı ve aşağı kaydırma yapan bir video

LazyColumn ile yapışkan bir başlık elde etmek için deneme amaçlı stickyHeader() işlevini kullanarak başlık içeriğini sağlayabilirsiniz:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ListWithHeader(items: List<Item>) {
    LazyColumn {
        stickyHeader {
            Header()
        }

        items(items) { item ->
            ItemRow(item)
        }
    }
}

Yukarıdaki "kişi listesi" örneği gibi birden çok üstbilgi içeren bir liste oluşturmak için şunları yapabilirsiniz:

// This ideally would be done in the ViewModel
val grouped = contacts.groupBy { it.firstName[0] }

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ContactsList(grouped: Map<Char, List<Contact>>) {
    LazyColumn {
        grouped.forEach { (initial, contactsForInitial) ->
            stickyHeader {
                CharacterHeader(initial)
            }

            items(contactsForInitial) { contact ->
                ContactListItem(contact)
            }
        }
    }
}

Kaydırma konumuna tepki verme

Birçok uygulamanın, kaydırma konumu ile öğe düzenindeki değişikliklere tepki vermesi ve bunları dinlemesi gerekir. Tembel bileşenler, LazyListState öğesini kaldırarak bu kullanım alanını destekler:

@Composable
fun MessageList(messages: List<Message>) {
    // Remember our own LazyListState
    val listState = rememberLazyListState()

    // Provide it to LazyColumn
    LazyColumn(state = listState) {
        // ...
    }
}

Basit kullanım alanlarında, uygulamaların genellikle yalnızca ilk görünür öğeyle ilgili bilgileri bilmesi gerekir. Bunun için LazyListState sağlar firstVisibleItemIndex ve firstVisibleItemScrollOffset özellikler.

Kullanıcının kaydırarak ilk öğeyi geçip geçmediğine bağlı olarak bir düğmeyi gösterme ve gizleme örneğini kullanırsak:

@Composable
fun MessageList(messages: List<Message>) {
    Box {
        val listState = rememberLazyListState()

        LazyColumn(state = listState) {
            // ...
        }

        // Show the button if the first visible item is past
        // the first item. We use a remembered derived state to
        // minimize unnecessary compositions
        val showButton by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex > 0
            }
        }

        AnimatedVisibility(visible = showButton) {
            ScrollToTopButton()
        }
    }
}

Durumu doğrudan kompozisyonda okumak, güncelleme yapmanız gerektiğinde yararlıdır kullanıcı arayüzü composable'ları oluşturur, ancak etkinliğin aynı bileşimde ele alınacaktır. Bunun yaygın bir örneği, kullanıcı belirli bir noktanın ötesine geçtiğinde bir Analytics etkinliği göndermektir. Bunu yapmak için etkili bir şekilde, snapshotFlow():

val listState = rememberLazyListState()

LazyColumn(state = listState) {
    // ...
}

LaunchedEffect(listState) {
    snapshotFlow { listState.firstVisibleItemIndex }
        .map { index -> index > 0 }
        .distinctUntilChanged()
        .filter { it }
        .collect {
            MyAnalyticsService.sendScrolledPastFirstItemEvent()
        }
}

LazyListState, layoutInfo mülkü aracılığıyla şu anda gösterilen tüm öğeler ve ekrandaki sınırları hakkında da bilgi sağlar. Daha fazla bilgi için LazyListLayoutInfo sınıfına bakın.

Kaydırma konumunu kontrol etme

Uygulamaların kaydırma konumuna tepki vermesinin yanı sıra kaydırma konumunu kontrol edebilmesi de yararlıdır. LazyListState scrollToItem() üzerinden bunu destekler işlevini "hemen" kaydırma konumu ve animateScrollToItem() yumuşak kaydırma olarak da bilinir.

@Composable
fun MessageList(messages: List<Message>) {
    val listState = rememberLazyListState()
    // Remember a CoroutineScope to be able to launch
    val coroutineScope = rememberCoroutineScope()

    LazyColumn(state = listState) {
        // ...
    }

    ScrollToTopButton(
        onClick = {
            coroutineScope.launch {
                // Animate scroll to the first item
                listState.animateScrollToItem(index = 0)
            }
        }
    )
}

Büyük veri kümeleri (sayfalama)

Sayfalama kitaplığı, uygulamaların büyük öğe listelerini desteklemesini sağlar. Bu kitaplık, gerektiğinde listenin küçük parçalarını yükleyip gösterir. Sayfalandırma 3.0 ve sonraki sürümler, androidx.paging:paging-compose kitaplığı aracılığıyla Oluştur desteği sağlar.

Sayfalandırılmış içeriğin listesini görüntülemek için collectAsLazyPagingItems() uzantı işlevini kullanabilir ve döndürülen LazyPagingItems değerini LazyColumn öğemizdeki items()'e iletebiliriz. Görünümlerdeki Sayfalama desteğine benzer şekilde, item değerinin null olup olmadığını kontrol ederek veriler yüklenirken yer tutucular gösterebilirsiniz:

@Composable
fun MessageList(pager: Pager<Int, Message>) {
    val lazyPagingItems = pager.flow.collectAsLazyPagingItems()

    LazyColumn {
        items(
            lazyPagingItems.itemCount,
            key = lazyPagingItems.itemKey { it.id }
        ) { index ->
            val message = lazyPagingItems[index]
            if (message != null) {
                MessageRow(message)
            } else {
                MessagePlaceholder()
            }
        }
    }
}

Yavaş düzenleri kullanmayla ilgili ipuçları

Yavaş oluşturulan düzenlerinizin amaçlandığı gibi çalıştığından emin olmak için dikkate alabileceğiniz birkaç ipucu vardır.

0 piksel boyutunda öğeler kullanmaktan kaçının

Bu durum, örneğin eşzamansız olarak yapmayı beklediğiniz senaryolarda gerçekleşebilir daha sonra listenizin öğelerini doldurmak için resimler gibi bazı verileri alma. Bu durumda, öğelerin yüksekliği 0 piksel olduğu ve tüm öğeler görüntü alanına sığabileceği için, tembel düzenin tüm öğelerini ilk ölçümde oluşturmasına neden olur. Öğeler yüklendikten ve yükseklikleri genişletildikten sonra, tembel düzenler, görüntü alanına sığmadıkları için ilk kez gereksiz yere oluşturulmuş diğer tüm öğeleri atar. Bunu önlemek için öğelerinize varsayılan boyutlandırmayı ayarlamanız gerekir. Böylece, Tembel düzen görüntü alanına sığabilen öğelerin doğru hesaplanması:

@Composable
fun Item(imageUrl: String) {
    AsyncImage(
        model = rememberAsyncImagePainter(model = imageUrl),
        modifier = Modifier.size(30.dp),
        contentDescription = null
        // ...
    )
}

Veriler eşzamansız olarak yüklendikten sonra öğelerinizin yaklaşık boyutunu bildiğinizde, öğelerinizin boyutunun yükleme öncesi ve sonrası aynı kalmasını sağlamak için bazı yer tutucular ekleyerek iyi bir uygulama yapabilirsiniz. Bu sayede, kaydırma konumunu doğru tutabilirsiniz.

Aynı yönde kaydırılabilir bileşenleri iç içe yerleştirmekten kaçının

Bu durum yalnızca, önceden tanımlanmış bir boyut olmadan kaydırılabilir alt öğelerin aynı yönde kaydırılabilir başka bir üst öğe içine yerleştirildiği durumlarda geçerlidir. Örneğin, dikey olarak kaydırılabilir bir Column üst öğenin içine sabit yükseklik içermeyen bir LazyColumn alt öğe yerleştirmeye çalışmak:

// throws IllegalStateException
Column(
    modifier = Modifier.verticalScroll(state)
) {
    LazyColumn {
        // ...
    }
}

Bunun yerine, tüm composable'larınızı sarmalayarak aynı sonucu elde edebilirsiniz. LazyColumn ve DSL'yi kullanarak farklı türde içerik. Bu sayede tek öğelerin yanı sıra birden fazla liste öğesini tek bir yerden yayınlayabilirsiniz:

LazyColumn {
    item {
        Header()
    }
    items(data) { item ->
        PhotoItem(item)
    }
    item {
        Footer()
    }
}

Farklı yön düzenlerini iç içe yerleştirdiğiniz durumlarda örneğin, kaydırılabilir üst Row ve alt LazyColumn öğelerine izin verilir:

Row(
    modifier = Modifier.horizontalScroll(scrollState)
) {
    LazyColumn {
        // ...
    }
}

Aynı yön düzenlerini kullanmaya devam ettiğiniz ancak iç içe yerleştirilmiş alt öğeler için sabit bir boyut belirlediğiniz durumlarda da:

Column(
    modifier = Modifier.verticalScroll(scrollState)
) {
    LazyColumn(
        modifier = Modifier.height(200.dp)
    ) {
        // ...
    }
}

Bir öğeye birden fazla öğe eklemekten kaçının

Bu örnekte, lambda adlı ikinci öğe bir blokta 2 öğe yayınlar:

LazyVerticalGrid(
    columns = GridCells.Adaptive(100.dp)
) {
    item { Item(0) }
    item {
        Item(1)
        Item(2)
    }
    item { Item(3) }
    // ...
}

Tembel düzenler bunu beklendiği gibi ele alarak öğeleri bir düzende yerleştirir. farklı öğelermiş gibi davranırlar. Ancak bunun için bazı işaretler bulabilirsiniz.

Birden fazla öğe bir öğenin parçası olarak yayınlandığında bir varlık gösterir, yani artık ayrı ayrı oluşturulamaz. Eğer öğesi ekranda görünür hale gelirse, oluşturulması ve ölçülmesi gerekir. Bu, kullanılırsa performansı düşürebilir aşırıya kaçmamak gerekir. Tüm öğeleri tek bir öğeye koymanın ekstrem bir örneği Bu, Tembel düzenlerin kullanılmasının amacını tamamen ortadan kaldırır. Olası performans sorunlarının yanı sıra, bir öğeye daha fazla öğe eklemek scrollToItem() ve animateScrollToItem() ile de etkileşime girer.

Bununla birlikte, bir öğeye birden fazla öğe yerleştirmenin geçerli kullanım alanları vardır. Mesela bir listeye ayırıcılar eklemek. Bağımsız öğeler olarak kabul edilmemeleri gerektiğinden, bölücülerin kaydırma dizelerini değiştirmesini istemezsiniz. Ayrıca, bölücüler küçük olduğundan performans da etkilenmez. Bir ayırıcının büyük olasılıkla öğe görünür hale gelmeden önce görünür; böylece önceki öğenin parçası olabilirler öğe:

LazyVerticalGrid(
    columns = GridCells.Adaptive(100.dp)
) {
    item { Item(0) }
    item {
        Item(1)
        Divider()
    }
    item { Item(2) }
    // ...
}

Özel düzenlemeler kullanmayı düşünün

Genellikle, yavaş listeler çok sayıda öğe içerir ve kaydırılabilir kapsayıcının boyutundan daha fazla yer kaplar. Ancak, listeniz az sayıda öğeyle doldurulduğunda, bunların nasıl konumlandırılacağına dair daha belirli gereklilikleri olabilir. görüntü alanında olması gerekir.

Bunun için özel sektör Arrangement LazyColumn'a iletebiliriz. Aşağıdaki örnekte, TopWithFooter nesnenin yalnızca arrange yöntemini uygulaması gerekir. İlk olarak, videoyu öğeleri üst üste koyacaksınız. İkinci olarak, kullanılan toplam yükseklik görüntü alanı yüksekliğinden düşükse altbilgi en altta konumlandırılır:

object TopWithFooter : Arrangement.Vertical {
    override fun Density.arrange(
        totalSize: Int,
        sizes: IntArray,
        outPositions: IntArray
    ) {
        var y = 0
        sizes.forEachIndexed { index, size ->
            outPositions[index] = y
            y += size
        }
        if (y < totalSize) {
            val lastIndex = outPositions.lastIndex
            outPositions[lastIndex] = totalSize - sizes.last()
        }
    }
}

contentType adlı kullanıcıyı eklemeyi düşünün

Compose 1.2'den itibaren, yavaş düzeninizin performansını en üst düzeye çıkarmak için listelerinize veya ızgaralarınıza contentType ekleyebilirsiniz. Bu, her biri için içerik türünü belirtmenize olanak tanır. bir liste veya ızgara oluşturduğunuz durumlarda, düzenin öğe türünden bahsedeceğiz:

LazyColumn {
    items(elements, contentType = { it.type }) {
        // ...
    }
}

contentType, Oluştur, yalnızca besteleri yeniden kullanabilir aynı türden öğeler arasında olmalıdır. Benzer yapıya sahip öğeler oluştururken yeniden kullanma daha verimli olduğundan, içerik türlerini belirtmek, Oluştur'un tamamen farklı bir B türü öğenin üzerine A türü bir öğe oluşturmaya çalışmamasını sağlar. Bu, kompozisyonun faydalarını en üst düzeye çıkarmaya ve Tembel düzen performansınız.

Performansı ölçme

Yavaşlamalı bir düzenin performansını yalnızca yayın modunda ve R8 optimizasyonu etkinken güvenilir bir şekilde ölçebilirsiniz. Hata ayıklama derlemelerinde, gecikmeli düzen kaydırma daha yavaş görünebilir. Bu konuda daha fazla bilgi edinmek için Oluşturma performansı başlıklı makaleyi okuyun.