Daftar dan petak

Banyak aplikasi perlu menampilkan koleksi item. Dokumen ini menjelaskan bagaimana Anda dapat melakukan ini secara efisien di Jetpack Compose.

Jika Anda tahu bahwa kasus penggunaan Anda tidak memerlukan scroll, Anda dapat menggunakan Column atau Row sederhana (bergantung pada arah), dan memunculkan setiap konten item dengan mengiterasi daftar dengan cara berikut:

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

Kita dapat membuat Column dapat di-scroll dengan menggunakan pengubah verticalScroll().

Daftar lambat

Jika Anda perlu menampilkan item dalam jumlah yang banyak (atau daftar dengan panjang yang tidak diketahui), menggunakan tata letak seperti Column dapat menyebabkan masalah performa, karena semua item akan disusun dan ditata baik terlihat atau tidak.

Compose menyediakan kumpulan komponen yang hanya mengomposisi dan menata letak item yang terlihat di area pandang komponen. Komponen ini meliputi LazyColumn dan LazyRow.

}

Seperti namanya, perbedaan antara LazyColumn dan LazyRow adalah pada orientasi tata letak item dan scroll. LazyColumn menghasilkan daftar scroll vertikal, dan LazyRow menghasilkan daftar scroll horizontal.

Komponen Lambat berbeda dengan sebagian besar tata letak di Compose. Alih-alih menerima parameter blok konten @Composable, yang memungkinkan aplikasi langsung memunculkan composable, komponen Lambat menyediakan blok LazyListScope.(). Blok LazyListScope ini menawarkan DSL yang memungkinkan aplikasi menjelaskan konten item. Komponen Lambat kemudian bertanggung jawab untuk menambahkan konten setiap item seperti yang diwajibkan oleh tata letak dan posisi scroll.

DSL LazyListScope

DSL LazyListScope menyediakan sejumlah fungsi untuk mendeskripsikan item dalam tata letak. Pada kasus yang paling dasar, item() menambahkan satu item, dan items(Int) menambahkan beberapa item:

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

Ada juga sejumlah fungsi ekstensi yang memungkinkan Anda menambahkan koleksi item, seperti List. Ekstensi ini memungkinkan kita memigrasikan contoh Column dengan mudah dari atas:

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

Ada juga varian dari fungsi ekstensi items() yang disebut itemsIndexed(), yang menyediakan indeks. Lihat referensi LazyListScope untuk detail selengkapnya.

Petak lambat

Composable LazyVerticalGrid dan LazyHorizontalGrid memberikan dukungan untuk menampilkan item dalam petak. Petak vertikal Lambat akan menampilkan itemnya dalam penampung yang dapat di-scroll secara vertikal, yang dibentangkan di beberapa kolom, sedangkan petak horizontal Lambat akan memiliki perilaku yang sama pada sumbu horizontal.

Petak memiliki kemampuan API canggih yang sama dengan daftar dan juga menggunakan DSL yang sangat mirip - LazyGridScope.() untuk mendeskripsikan konten.

Screenshot ponsel yang menampilkan petak foto

Parameter columns di parameter LazyVerticalGrid dan rows di LazyHorizontalGrid mengontrol cara sel terbentuk menjadi kolom atau baris. Contoh berikut menampilkan item dalam petak, menggunakan GridCells.Adaptive untuk menetapkan lebar masing-masing kolom minimal 128.dp:

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

LazyVerticalGrid memungkinkan Anda menentukan lebar item, lalu petak akan sesuai dengan sebanyak mungkin kolom. Lebar apa pun yang tersisa didistribusikan secara merata di antara kolom, setelah jumlah kolom dihitung. Cara adaptif pengukuran ini sangat berguna untuk menampilkan kumpulan item di berbagai ukuran layar.

Jika mengetahui jumlah kolom yang akan digunakan, Anda dapat memberikan instance GridCells.Fixed yang berisi jumlah kolom yang diperlukan.

Jika desain Anda hanya memerlukan item tertentu untuk memiliki dimensi non-standar, Anda dapat menggunakan dukungan petak untuk menyediakan span kolom kustom untuk item. Tentukan span kolom dengan parameter span dari metode item dan items LazyGridScope DSL. maxLineSpan, salah satu nilai cakupan span, sangat berguna saat Anda menggunakan ukuran adaptif, karena jumlah kolom tidak tetap. Contoh ini menunjukkan cara memberikan span baris lengkap:

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

Petak tidak teratur lambat

LazyVerticalStaggeredGrid dan LazyHorizontalStaggeredGrid adalah composable yang memungkinkan Anda membuat petak item yang dimuat lambat dan bertingkat. Petak bertahap vertikal lambat menampilkan itemnya dalam penampung yang dapat di-scroll secara vertikal yang membentang di beberapa kolom dan memungkinkan setiap item memiliki tinggi yang berbeda. Petak horizontal lambat memiliki perilaku yang sama pada sumbu horizontal dengan item yang memiliki lebar berbeda.

Cuplikan berikut adalah contoh dasar penggunaan LazyVerticalStaggeredGrid dengan lebar 200.dp per item:

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

Gambar 1. Contoh petak vertikal acak lambat

Untuk menetapkan jumlah kolom tetap, Anda dapat menggunakan StaggeredGridCells.Fixed(columns), bukan StaggeredGridCells.Adaptive. Tindakan ini membagi lebar yang tersedia dengan jumlah kolom (atau baris untuk petak horizontal), dan membuat setiap item menggunakan lebar tersebut (atau tinggi untuk petak horizontal):

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

Petak gambar lambat yang tidak teratur di Compose
Gambar 2. Contoh petak vertikal acak lambat dengan kolom tetap

Padding konten

Terkadang Anda perlu menambahkan padding di sekitar tepi konten. Komponen lambat memungkinkan Anda meneruskan PaddingValues tertentu ke parameter contentPadding untuk mendukung ini:

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

Dalam contoh ini, kami menambahkan 16.dp padding ke tepi horizontal (kiri dan kanan), lalu 8.dp ke bagian atas dan bawah konten.

Perhatikan bahwa padding ini berlaku untuk konten, bukan untuk LazyColumn itu sendiri. Pada contoh di atas, item pertama akan menambahkan padding 8.dp ke bagian atas, item terakhir akan menambahkan 8.dp ke bagian bawah, dan semua item akan memiliki padding 16.dp di kiri dan kanan.

Jarak konten

Untuk menambahkan spasi di antara item, Anda dapat menggunakan Arrangement.spacedBy(). Contoh di bawah ini menambahkan 4.dp spasi di antara setiap item:

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

Demikian pula untuk LazyRow:

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

Namun, petak menerima pengaturan vertikal dan horizontal:

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

Kunci item

Secara default, setiap status item dikunci sesuai posisi item dalam daftar atau petak. Namun, hal ini dapat menyebabkan masalah jika set data berubah, karena item yang mengubah posisi secara efektif kehilangan status yang diingat. Jika Anda membayangkan skenario LazyRow dalam LazyColumn, jika baris mengubah posisi item, pengguna akan kehilangan posisi scroll dalam baris tersebut.

Untuk mengatasi hal ini, Anda dapat memberikan kunci yang stabil dan unik untuk setiap item, dengan memberikan pemblokiran ke parameter key. Dengan menyediakan kunci yang stabil, status item akan konsisten di seluruh perubahan set data:

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

Dengan menyediakan kunci, Anda membantu Compose menangani pengurutan ulang dengan benar. Misalnya, jika item Anda berisi status yang diingat, kunci setelan akan memungkinkan Compose memindahkan status ini bersama item tersebut, saat posisinya berubah.

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

Namun, ada satu batasan pada jenis yang dapat Anda gunakan sebagai kunci item. Jenis kunci harus didukung oleh Bundle, mekanisme Android untuk mempertahankan status saat Aktivitas dibuat ulang. Bundle mendukung jenis seperti primitive, enum, atau Parcelable.

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

Kunci harus didukung oleh Bundle sehingga rememberSaveable di dalam composable item dapat dipulihkan saat Aktivitas dibuat ulang, atau bahkan saat Anda men-scroll keluar dari item ini dan men-scroll kembali.

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

Animasi item

Jika menggunakan widget RecyclerView, Anda akan mengetahui bahwa widget tersebut menganimasikan perubahan item secara otomatis. Tata letak lambat menyediakan fungsi yang sama untuk penyusunan ulang item. API ini sederhana - Anda hanya perlu menetapkan pengubah animateItem ke konten item:

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()) {
            // ...
        }
    }
}

Anda bahkan dapat memberikan spesifikasi animasi kustom, jika perlu:

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)
            )
        ) {
            // ...
        }
    }
}

Pastikan Anda menyediakan kunci untuk item sehingga Anda dapat menemukan posisi baru untuk elemen yang dipindahkan.

Header sticky (eksperimental)

Pola 'header sticky' berguna saat menampilkan daftar data yang dikelompokkan. Di bawah ini, Anda dapat melihat contoh 'daftar kontak', yang dikelompokkan berdasarkan setiap inisial kontak:

Video ponsel yang di-scroll ke atas dan ke bawah melalui daftar kontak

Untuk mendapatkan header sticky dengan LazyColumn, Anda dapat menggunakan fungsi stickyHeader() eksperimental, yang menyediakan konten header:

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

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

Untuk mencapai daftar dengan beberapa header, seperti contoh 'daftar kontak' di atas, Anda dapat menggunakan:

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

Bereaksi terhadap posisi scroll

Banyak aplikasi yang perlu bereaksi dan memproses perubahan tata letak item dan posisi scroll. Komponen Lambat mendukung kasus penggunaan ini dengan menarik LazyListState:

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

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

Untuk kasus penggunaan sederhana, aplikasi biasanya hanya perlu mengetahui informasi tentang item pertama yang terlihat. Untuk ini, LazyListState memberikan properti firstVisibleItemIndex dan firstVisibleItemScrollOffset.

Jika kita menggunakan contoh yang menampilkan dan menyembunyikan tombol berdasarkan apakah pengguna telah men-scroll melewati item pertama:

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

Membaca status secara langsung dalam komposisi berguna saat Anda perlu mengupdate composable UI lain, tetapi ada juga skenario saat peristiwa tidak perlu ditangani dalam komposisi yang sama. Contoh umum dari hal ini adalah mengirimkan peristiwa analisis setelah pengguna men-scroll melewati titik tertentu. Untuk menangani masalah ini secara efisien, kita dapat menggunakan snapshotFlow():

val listState = rememberLazyListState()

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

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

LazyListState juga memberikan informasi tentang semua item yang saat ini ditampilkan dan batasnya di layar, melalui properti layoutInfo. Lihat class LazyListLayoutInfo untuk mengetahui informasi selengkapnya.

Mengontrol posisi scroll

Selain merespons posisi scroll, sebaiknya aplikasi juga dapat mengontrol posisi scroll. LazyListState mendukung ini melalui fungsi scrollToItem(), yang 'segera' men-snap posisi scroll, dan animateScrollToItem() yang men-scroll menggunakan animasi (juga dikenal sebagai scroll halus):

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

Set data besar (paging)

Dengan library Paging, aplikasi dapat mendukung sejumlah besar item, memuat, dan menampilkan potongan daftar kecil sesuai kebutuhan. Paging 3.0 dan yang lebih baru menyediakan dukungan Compose melalui library androidx.paging:paging-compose.

Untuk menampilkan daftar konten halaman, kita dapat menggunakan fungsi ekstensi collectAsLazyPagingItems(), lalu meneruskan LazyPagingItems yang ditampilkan ke items() di LazyColumn. Serupa dengan dukungan Paging dalam tampilan, Anda dapat menampilkan placeholder saat data dimuat dengan memeriksa apakah item adalah null:

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

Tips menggunakan tata letak Lambat

Ada beberapa tips yang dapat Anda pertimbangkan untuk memastikan tata letak Lambat berfungsi sebagaimana mestinya.

Menghindari penggunaan item berukuran 0 piksel

Hal ini dapat terjadi dalam skenario saat, misalnya, Anda ingin mengambil beberapa data secara asinkron seperti gambar, untuk mengisi item daftar Anda pada tahap berikutnya. Tindakan tersebut akan menyebabkan tata letak Lambat menyusun semua itemnya dalam pengukuran pertama, karena tingginya 0 piksel dan dapat memuat semuanya di area pandang. Setelah item dimuat dan tingginya diperluas, tata letak Lambat akan menghapus semua item lain yang belum perlu disusun untuk pertama kalinya karena sebenarnya tidak dapat menyesuaikan dengan area pandang. Untuk menghindari hal ini, Anda harus menetapkan ukuran default ke item sehingga tata letak Lambat dapat menghitung jumlah item yang benar-benar dapat dimuat di area pandang dengan benar:

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

Bila Anda mengetahui perkiraan ukuran item setelah data dimuat secara asinkron, praktik yang baik adalah memastikan ukuran item tetap sama sebelum dan setelah pemuatan, misalnya, dengan menambahkan beberapa placeholder. Ini akan membantu mempertahankan posisi scroll yang benar.

Menghindari penyusunan bertingkat komponen yang dapat di-scroll di arah yang sama

Ini hanya berlaku untuk kasus saat menyusun bertingkat turunan yang dapat di-scroll tanpa ukuran yang telah ditetapkan di dalam induk yang dapat di-scroll dan memiliki arah sama. Misalnya, mencoba menyusun bertingkat LazyColumn turunan tanpa tinggi tetap di dalam induk Column yang dapat di-scroll secara vertikal:

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

Sebaliknya, hasil yang sama dapat dicapai dengan menggabungkan semua composable Anda di dalam satu LazyColumn induk dan menggunakan DSL-nya untuk meneruskan berbagai jenis konten. Hal ini memungkinkan kemunculan item tunggal, serta beberapa item daftar, semuanya di satu tempat:

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

Perlu diingat bahwa saat Anda menyusun tata letak arah yang berbeda secara bertingkat, misalnya Row induk yang dapat di-scroll dan LazyColumn turunan, akan diizinkan:

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

Begitu juga dengan saat Anda masih menggunakan tata letak arah yang sama, tetapi juga menetapkan ukuran tetap ke turunan bertingkat:

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

Berhati-hati dalam menempatkan beberapa elemen dalam satu item

Dalam contoh ini, lambda item kedua memunculkan 2 item dalam satu blok:

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

Tata letak lambat akan menangani hal ini seperti yang diharapkan - tata letak akan menata letak elemen satu per satu seolah-olah merupakan item yang berbeda. Namun, ada beberapa masalah saat melakukannya.

Jika beberapa elemen ditampilkan sebagai bagian dari satu item, elemen tersebut ditangani sebagai satu entitas, yang berarti elemen tersebut tidak dapat lagi disusun satu per satu. Jika satu elemen terlihat di layar, semua elemen yang sesuai dengan item tersebut harus dikomposisi dan diukur. Hal ini dapat mengganggu performa jika digunakan secara berlebihan. Untuk menempatkan semua elemen dalam satu item secara ekstrem, tujuan menggunakan tata letak Lambat akan sepenuhnya gagal. Selain potensi masalah performa, menempatkan lebih banyak elemen dalam satu item juga akan mengganggu scrollToItem() & animateScrollToItem().

Namun, ada kasus penggunaan yang valid untuk menempatkan beberapa elemen dalam satu item, seperti memiliki pembagi di dalam daftar. Anda tidak ingin pembagi mengubah indeks scroll, karena tidak boleh dianggap sebagai elemen independen. Selain itu, performa tidak akan terpengaruh karena pembagi kecil. Pembagi mungkin perlu terlihat saat item di depannya terlihat, sehingga dapat menjadi bagian dari item sebelumnya:

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

Mencoba menggunakan pengaturan kustom

Biasanya daftar Lambat memiliki banyak item, dan menempati lebih dari ukuran penampung scroll. Namun, jika daftar diisi dengan sedikit item, desain Anda dapat memiliki persyaratan yang lebih spesifik terkait cara penempatan ini dalam area pandang.

Untuk mencapainya, Anda dapat menggunakan vertical kustom Arrangement dan meneruskannya ke LazyColumn. Pada contoh berikut, objek TopWithFooter hanya perlu mengimplementasikan metode arrange. Pertama, item akan diposisikan satu per satu. Kedua, jika total tinggi yang digunakan lebih rendah dari tinggi area pandang, footer akan diposisikan di bawah:

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

Mencoba menambahkan contentType

Mulai dari Compose 1.2, untuk memaksimalkan performa tata letak Lambat, sebaiknya coba tambahkan contentType ke daftar atau petak Anda. Hal ini memungkinkan Anda menentukan jenis konten untuk setiap item tata letak, ketika Anda mengomposisi daftar atau petak yang terdiri dari beberapa jenis item:

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

Saat Anda menyediakan contentType, Compose dapat menggunakan kembali komposisi hanya di antara item dari jenis yang sama. Karena penggunaan ulang lebih efisien saat Anda mengomposisi item dengan struktur yang serupa, menyediakan jenis konten akan memastikan Compose lebih memprioritaskan untuk mengomposisi item berjenis A daripada item yang benar-benar berbeda dari jenis B. Hal ini membantu memaksimalkan manfaat penggunaan ulang komposisi dan performa tata letak Lambat.

Mengukur performa

Anda hanya dapat mengukur performa tata letak Lambat dengan andal saat berjalan dalam mode rilis dan dengan pengoptimalan R8 diaktifkan. Pada build debug, scroll tata letak Lambat mungkin tampak lebih lambat. Untuk informasi selengkapnya tentang hal ini, baca Performa Compose.