Nhiều ứng dụng cần hiển thị bộ sưu tập các mục. Tài liệu này giải thích cách bạn có thể thực hiện việc này một cách hiệu quả trong Jetpack Compose.
Nếu biết rằng trường hợp sử dụng của bạn không cần phải cuộn, bạn nên sử dụng Column
hoặc Row
đơn giản (tuỳ thuộc vào đường đi) và phát ra nội dung của mỗi mục bằng cách lặp lại trên một danh sách theo cách sau:
@Composable fun MessageList(messages: List<Message>) { Column { messages.forEach { message -> MessageRow(message) } } }
Chúng tôi có thể làm cho Column
có thể cuộn bằng cách sử dụng công cụ sửa đổi verticalScroll()
.
Danh sách lazy
Nếu bạn cần hiển thị một số lượng lớn các mục (hoặc một danh sách có độ dài không xác định), thì việc sử dụng bố cục như Column
có thể gây ra trở ngại về hiệu suất, vì tất cả các mục sẽ được tạo và bố trí cho dù chúng có hiển thị hay không.
Compose cung cấp một tập hợp các thành phần chỉ soạn và bố trí các mục hiển thị trong khung nhìn của thành phần. Các thành phần này bao gồm
LazyColumn
và
LazyRow
.
Như đã thể hiện trong tên gọi, sự khác biệt giữa
LazyColumn
và
LazyRow
là hướng sắp xếp bố cục các mục và thanh cuộn. LazyColumn
tạo danh sách cuộn theo chiều dọc và LazyRow
tạo danh sách cuộn theo chiều ngang.
Các thành phần tải từng phần sẽ khác với hầu hết các bố cục trong công cụ Compose. Thay vì chấp nhận tham số của khối nội dung @Composable
, cho phép các ứng dụng trực tiếp phát hành thành phần kết hợp, các thành phần tải từng phần sẽ cung cấp một khối LazyListScope.()
. Khối LazyListScope
này cung cấp một DSL, cho phép các ứng dụng mô tả nội dung của mục. Theo đó, thành phần tải từng phần sẽ chịu trách nhiệm thêm nội dung của từng mục theo yêu cầu của bố cục và vị trí cuộn.
LazyListScope
DSL
DSL của LazyListScope
cung cấp một số hàm để mô tả các mục
trong bố cục. Về cơ bản,
item()
thêm một mục duy nhất và
items(Int)
thêm nhiều mục:
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") } }
Ngoài ra, một số hàm mở rộng cho phép bạn thêm
bộ sưu tập các mục, chẳng hạn như List
. Các phần mở rộng này cho phép dễ dàng
di chuyển mẫu Column
từ bên trên:
/** * import androidx.compose.foundation.lazy.items */ LazyColumn { items(messages) { message -> MessageRow(message) } }
Ngoài ra, còn có một biến thể của
hàm mở rộng items()
gọi là
itemsIndexed()
.
Hàm này cung cấp chỉ mục đó. Vui lòng xem tài liệu tham khảo LazyListScope
để biết thêm thông tin chi tiết.
Lưới lazy
Các thành phần LazyVerticalGrid
và LazyHorizontalGrid
hỗ trợ việc hiển thị các mục trong lưới. Lưới dọc lazy sẽ hiển thị các mục của nó trong một vùng chứa có thể cuộn theo chiều dọc, kéo dài qua nhiều cột, trong khi các lưới ngang Lazy sẽ có cùng hành vi trên trục hoành.
Lưới có cùng khả năng API như danh sách và cũng sử dụng DSL rất giống nhau – LazyGridScope.()
để mô tả nội dung.
Tham số columns
trong LazyVerticalGrid
và tham số rows
trong LazyHorizontalGrid
kiểm soát cách các ô được tạo thành cột hoặc hàng. Ví dụ dưới đây hiển thị các mục trong một lưới, sử dụng GridCells.Adaptive
để đặt chiều rộng tối thiểu cho mỗi cột là 128.dp
:
LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 128.dp) ) { items(photos) { photo -> PhotoItem(photo) } }
LazyVerticalGrid
cho phép bạn chỉ định chiều rộng của các mục để lưới có thể vừa vặn với nhiều cột nhất có thể. Chiều rộng còn lại sẽ được phân bổ đồng đều cho các cột sau khi tính toán số lượng cột.
Phương pháp định cỡ thích ứng này đặc biệt hữu ích khi hiển thị các nhóm mục trên nhiều kích thước màn hình khác nhau.
Nếu biết chính xác số lượng cột cần sử dụng, bạn có thể cung cấp một
bản sao của
GridCells.Fixed
chứa số lượng cột bắt buộc.
Nếu thiết kế của bạn chỉ yêu cầu một số mục nhất định có kích thước không chuẩn, bạn có thể sử dụng chức năng hỗ trợ lưới để kéo dài khoảng cột tuỳ chỉnh cho các mục.
Hãy chỉ định khoảng cột bằng tham số span
của phương thức LazyGridScope DSL
item
và items
.
maxLineSpan
, một trong các giá trị của phạm vi khoảng, đặc biệt hữu ích khi bạn sử dụng kích thước thích ứng vì số lượng cột không cố định.
Ví dụ này chỉ ra cách cung cấp khoảng hàng đầy đủ:
LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 30.dp) ) { item(span = { // LazyGridItemSpanScope: // maxLineSpan GridItemSpan(maxLineSpan) }) { CategoryCard("Fruits") } // ... }
Lưới so le tải từng phần
LazyVerticalStaggeredGrid
và LazyHorizontalStaggeredGrid
là các thành phần kết hợp cho phép bạn tạo một lưới các mục được tải từng phần, xếp kề.
Lưới dọc theo kiểu bậc thang tải từng phần hiển thị các mục trong một vùng chứa có thể cuộn theo chiều dọc, kéo dài qua nhiều cột và cho phép các mục riêng lẻ có chiều cao khác nhau. Các lưới ngang tải từng phần có hành vi tương tự trên
trục hoành với các mục có chiều rộng khác nhau.
Đoạn mã sau đây là một ví dụ cơ bản về cách sử dụng LazyVerticalStaggeredGrid
có chiều rộng là 200.dp
cho mỗi mục:
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() )
Để đặt số lượng cột cố định, bạn có thể sử dụng
StaggeredGridCells.Fixed(columns)
thay vì StaggeredGridCells.Adaptive
.
Thao tác này chia chiều rộng có sẵn cho số cột (hoặc hàng đối với lưới ngang) và mỗi mục chiếm chiều rộng (hoặc chiều cao đối với lưới ngang) đó:
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() )
Khoảng đệm nội dung
Đôi khi, bạn cần thêm khoảng đệm quanh các cạnh của nội dung. Các thành phần tải từng phần cho phép bạn chuyển một số
PaddingValues
đến thông số contentPadding
để hỗ trợ việc này:
LazyColumn( contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), ) { // ... }
Trong ví dụ này, chúng ta thêm 16.dp
khoảng đệm vào các cạnh ngang (bên trái
và bên phải), sau đó thêm 8.dp
vào phần đầu và cuối nội dung.
Xin lưu ý rằng khoảng đệm này áp dụng cho nội dung chứ không áp dụng cho
LazyColumn
. Trong ví dụ trên, mục đầu tiên sẽ thêm 8.dp
khoảng đệm lên đầu, mục cuối cùng sẽ thêm 8.dp
vào dưới cùng và tất cả
mục sẽ có 16.dp
khoảng đệm trên sang trái và phải.
Giãn cách nội dung
Để thêm khoảng cách giữa các mục, bạn có thể sử dụng
Arrangement.spacedBy()
.
Ví dụ dưới đây sẽ thêm 4.dp
khoảng cách ở giữa mỗi mục:
LazyColumn( verticalArrangement = Arrangement.spacedBy(4.dp), ) { // ... }
Tương tự cho LazyRow
:
LazyRow( horizontalArrangement = Arrangement.spacedBy(4.dp), ) { // ... }
Tuy nhiên, lưới chấp nhận cả cách sắp xếp dọc và ngang:
LazyVerticalGrid( columns = GridCells.Fixed(2), verticalArrangement = Arrangement.spacedBy(16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { items(photos) { item -> PhotoItem(item) } }
Khoá mục
Theo mặc định, trạng thái của mỗi mục được khoá dựa vào vị trí của mục trong danh sách hoặc lưới. Tuy nhiên, điều này có thể gây ra sự cố nếu tập dữ liệu thay đổi, vì các mục thay đổi vị trí sẽ mất bất kỳ trạng thái nào được ghi nhớ. Nếu bạn hình dung
tình huống LazyRow
trong một LazyColumn
, nếu hàng thay đổi vị trí mục,
thì sau đó người dùng sẽ mất vị trí cuộn trong hàng.
Để xử lý điều này, bạn có thể cung cấp một khoá ổn định và duy nhất cho mỗi mục, cung cấp
một khối cho thông số key
. Việc cung cấp khoá ổn định cho phép trạng thái mục nhất quán qua các thay đổi của tập dữ liệu:
LazyColumn { items( items = messages, key = { message -> // Return a stable + unique key for the item message.id } ) { message -> MessageRow(message) } }
Bằng cách cung cấp các khoá, bạn giúp Compose xử lý việc sắp xếp lại thứ tự một cách chính xác. Ví dụ: nếu mục của bạn chứa trạng thái đã nhớ, các khoá cài đặt sẽ cho phép Compose di chuyển trạng thái này cùng với mục khi vị trí của mục thay đổi.
LazyColumn { items(books, key = { it.id }) { val rememberedValue = remember { Random.nextInt() } } }
Tuy nhiên, có một hạn chế về những loại bạn có thể sử dụng làm khoá mục.
Loại khoá này phải được hỗ trợ bởi Bundle
, là cơ chế của Android để giữ lại trạng thái khi Hoạt động được tạo lại. Bundle
hỗ trợ các loại như dữ liệu gốc, enum hoặc Parcelables.
LazyColumn { items(books, key = { // primitives, enums, Parcelable, etc. }) { // ... } }
Bundle
phải hỗ trợ khoá này để có thể khôi phục rememberSaveable
bên trong thành phần kết hợp mục khi Hoạt động được tạo lại, hoặc thậm chí khi bạn cuộn ra khỏi mục này và cuộn trở lại.
LazyColumn { items(books, key = { it.id }) { val rememberedValue = rememberSaveable { Random.nextInt() } } }
Ảnh động theo mục
Nếu đã từng sử dụng tiện ích RecyclerView, bạn sẽ biết là tiện ích đó tự động tạo ảnh động cho các thay đổi mục.
Bố cục lazy cung cấp chức năng tương tự để sắp xếp lại mục.
API này rất đơn giản – bạn chỉ cần đặt công cụ sửa đổi animateItemPlacement
cho nội dung mục:
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()) { // ... } } }
Bạn thậm chí có thể cung cấp thông số kỹ thuật về ảnh động tuỳ chỉnh, nếu bạn cần:
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) ) ) { // ... } } }
Đảm bảo bạn cung cấp khoá cho các mục của mình để có thể tìm thấy vị trí mới cho phần tử đã di chuyển.
Ngoài việc sắp xếp lại thứ tự, chúng tôi cũng đang phát triển các tính năng thêm và xoá cho ảnh động của mục. Bạn có thể theo dõi tiến trình trong vấn đề 150812265.
Tiêu đề cố định (thử nghiệm)
Mẫu "tiêu đề cố định" rất hữu ích khi hiển thị danh sách dữ liệu được phân nhóm. Dưới đây là bạn có thể xem ví dụ về "danh sách liên hệ", được nhóm theo tên viết tắt của mỗi liên hệ:
Để đạt được tiêu đề cố định bằng LazyColumn
, bạn có thể sử dụng hàm
stickyHeader()
thử nghiệm, cung cấp nội dung tiêu đề như sau:
@OptIn(ExperimentalFoundationApi::class) @Composable fun ListWithHeader(items: List<Item>) { LazyColumn { stickyHeader { Header() } items(items) { item -> ItemRow(item) } } }
Để đạt được danh sách có nhiều tiêu đề, chẳng hạn như "danh sách liên hệ" ở trên, bạn có thể làm như sau:
// 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) } } } }
Phản ứng với vị trí cuộn
Nhiều ứng dụng cần phản ứng và lắng nghe các thay đổi về vị trí cuộn và bố cục mục.
Các thành phần tải từng phần hỗ trợ trường hợp sử dụng này bằng cách nâng cấp LazyListState
:
@Composable fun MessageList(messages: List<Message>) { // Remember our own LazyListState val listState = rememberLazyListState() // Provide it to LazyColumn LazyColumn(state = listState) { // ... } }
Đối với các trường hợp sử dụng đơn giản, các ứng dụng thường chỉ cần biết thông tin về mục hiển thị đầu tiên. Với nội dung này, LazyListState
cung cấp các thuộc tính firstVisibleItemIndex
và firstVisibleItemScrollOffset
.
Nếu chúng ta sử dụng ví dụ về cách hiển thị và ẩn nút dựa trên việc người dùng đã cuộn qua mục đầu tiên hay chưa:
@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() } } }
Việc đọc trạng thái ngay trong nội dung hợp thành sẽ hữu ích khi bạn cần cập nhật
các thành phần kết hợp của giao diện người dùng khác, nhưng cũng có các trường hợp mà sự kiện không cần
phải xử lý trong cùng một nội dung hợp thành. Một ví dụ phổ biến về việc này là gửi một
sự kiện phân tích khi người dùng cuộn qua một điểm nhất định. Để xử lý việc này
một cách hiệu quả, bạn có thể sử dụng
snapshotFlow()
:
val listState = rememberLazyListState() LazyColumn(state = listState) { // ... } LaunchedEffect(listState) { snapshotFlow { listState.firstVisibleItemIndex } .map { index -> index > 0 } .distinctUntilChanged() .filter { it } .collect { MyAnalyticsService.sendScrolledPastFirstItemEvent() } }
LazyListState
cũng cung cấp thông tin về tất cả các mục hiện đang được hiển thị và giới hạn của các mục đó trên màn hình, thông qua thuộc tính layoutInfo
. Hãy xem lớp
LazyListLayoutInfo
để biết thêm thông tin.
Kiểm soát vị trí cuộn
Bên cạnh việc phản ứng với vị trí cuộn, việc ứng dụng có thể
kiểm soát vị trí cuộn cũng hữu ích.
LazyListState
hỗ trợ nội dung này thông qua hàm scrollToItem()
.
Hành động hỗ trợ này 'ngay lập tức' sẽ ghim
vị trí cuộn và animateScrollToItem()
cuộn bằng cách sử dụng ảnh động (còn gọi là cuộn mượt):
@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) } } ) }
Các tập dữ liệu lớn (phân trang)
Thư viện Paging cho phép các ứng dụng
hỗ trợ danh sách lớn các mục, tải và hiển thị nhiều danh sách nhỏ trong danh sách
nếu cần. Paging phiên bản 3.0 trở lên cung cấp dịch vụ hỗ trợ sử dụng công cụ Compose thông qua thư viện
androidx.paging:paging-compose
.
Để hiển thị danh sách nội dung được phân trang, chúng ta có thể sử dụng hàm mở rộng
collectAsLazyPagingItems()
,
sau đó chuyển
LazyPagingItems
trả về vào items()
trong LazyColumn
của mình. Tương tự như hỗ trợ Paging trong các chế độ xem, bạn có thể
hiển thị các trình giữ chỗ trong khi dữ liệu tải bằng cách kiểm tra xem item
có phải là null
không:
@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() } } } }
Mẹo sử dụng bố cục Lazy
Bạn có thể tham khảo một số mẹo để đảm bảo bố cục Lazy hoạt động như dự kiến.
Tránh sử dụng các mục có kích thước 0 pixel
Điều này có thể xảy ra trong những trường hợp như khi bạn dự kiến truy xuất không đồng bộ một số dữ liệu như hình ảnh, để lấp đầy các mục trong danh sách ở giai đoạn sau. Điều đó sẽ khiến bố cục Lazy sắp xếp tất cả các mục của nó trong lần đo đầu tiên, vì chiều cao của chúng là 0 pixel và có thể vừa với tất cả các mục trong khung nhìn. Khi các mục đã tải và chiều cao của chúng được mở rộng, các bố cục Lazy sẽ loại bỏ những mục khác được tạo một cách không cần thiết trong lần đầu tiên, vì thực tế thì chúng không thể vừa với khung nhìn. Để tránh trường hợp này, bạn nên đặt kích thước mặc định cho các mục của mình, để bố cục Lazy có thể thực hiện tính toán chính xác số lượng mục thực sự có thể vừa với khung nhìn:
@Composable fun Item(imageUrl: String) { AsyncImage( model = rememberAsyncImagePainter(model = imageUrl), modifier = Modifier.size(30.dp), contentDescription = null // ... ) }
Khi biết kích thước gần đúng của các mục sau khi tải dữ liệu không đồng bộ, bạn nên đảm bảo kích thước của các mục không thay đổi trước và sau khi tải, bằng cách thêm vào một số phần giữ chỗ. Việc này giúp duy trì vị trí cuộn chính xác.
Tránh lồng các thành phần có thể cuộn theo cùng một hướng
Điều này chỉ áp dụng cho những trường hợp khi lồng các con có thể cuộn được mà không có kích thước xác định trước bên trong cha mẹ có thể cuộn theo cùng một hướng khác. Chẳng hạn cố gắng lồng một thành phần con LazyColumn
không có chiều cao cố định trong thành phần mẹ Column
có thể cuộn được theo chiều dọc:
// throws IllegalStateException Column( modifier = Modifier.verticalScroll(state) ) { LazyColumn { // ... } }
Thay vào đó, bạn có thể đạt được kết quả tương tự bằng cách gói tất cả các thành phần kết hợp bên trong một LazyColumn
mẹ và sử dụng DSL của thành phần đó để truyền các loại nội dung khác nhau. Điều này cho phép tạo ra các mục riêng lẻ, cũng như nhiều mục danh sách ở cùng một nơi:
LazyColumn { item { Header() } items(data) { item -> PhotoItem(item) } item { Footer() } }
Vui lòng lưu ý trong trường hợp bạn lồng những bố cục có hướng khác nhau, chẳng hạn như chế độ mẹ có thể cuộn được Row
và con LazyColumn
, được phép:
Row( modifier = Modifier.horizontalScroll(scrollState) ) { LazyColumn { // ... } }
Cũng như các trường hợp bạn vẫn sử dụng bố cục cùng hướng nhưng đồng thời đặt kích thước cố định cho các thành phần con lồng nhau:
Column( modifier = Modifier.verticalScroll(scrollState) ) { LazyColumn( modifier = Modifier.height(200.dp) ) { // ... } }
Cần cảnh giác khi đặt nhiều phần tử vào một mục
Ở ví dụ này, mục thứ hai chứa hàm lambda xuất ra 2 mục trong một khối:
LazyVerticalGrid( columns = GridCells.Adaptive(100.dp) ) { item { Item(0) } item { Item(1) Item(2) } item { Item(3) } // ... }
Bố cục lazy sẽ xử lý điều này như mong đợi - chúng sẽ bố trí các phần tử lần lượt như thể chúng là các mục khác nhau. Tuy nhiên, cũng có một vài bất cập khi làm như vậy.
Khi nhiều phần tử được xuất ra dưới dạng một phần của một mục, các phần tử đó sẽ được xử lý như một thực thể, nghĩa là không thể tạo riêng từng phần tử được nữa. Nếu một phần tử hiển thị trên màn hình, thì tất cả các phần tử tương ứng với mục đó phải được sắp xếp và đo lường. Điều này có thể ảnh hưởng đến hiệu suất nếu sử dụng quá mức. Trong trường hợp đặc biệt khi đặt tất cả các phần tử vào một mục, mục đó sẽ hoàn toàn đánh bại mục đích sử dụng bố cục Lazy. Ngoài những bất cập tiềm ẩn về hiệu suất, việc đặt thêm nhiều phần tử vào cùng một mục cũng sẽ ảnh hưởng đến scrollToItem()
và animateScrollToItem()
.
Tuy nhiên, có những trường hợp sử dụng hợp lệ cho việc đưa nhiều phần tử vào một mục, chẳng hạn như bộ chia bên trong một danh sách. Bạn không muốn bộ chia thay đổi các chỉ số cuộn, vì chúng không được coi là các phần tử độc lập. Ngoài ra, hiệu suất sẽ không bị ảnh hưởng vì các bộ chia nhỏ. Một bộ chia có thể sẽ cần được hiển thị khi mục trước nó hiển thị, để bộ chia có thể nằm trong mục trước đó:
LazyVerticalGrid( columns = GridCells.Adaptive(100.dp) ) { item { Item(0) } item { Item(1) Divider() } item { Item(2) } // ... }
Cân nhắc sử dụng cách sắp xếp tuỳ chỉnh
Thông thường, danh sách Lazy có nhiều mục và các mục này chiếm nhiều hơn kích thước của vùng chứa cuộn. Tuy nhiên, khi danh sách của bạn có ít mục, bạn có thể thiết kế các yêu cầu cụ thể hơn về cách đặt những mục này trong khung nhìn.
Để đạt được điều này, bạn có thể sử dụng Arrangement
tuỳ chỉnh theo chiều dọc và truyền tham số này đến LazyColumn
. Trong ví dụ sau, đối tượng TopWithFooter
chỉ cần triển khai phương thức arrange
. Đầu tiên, nó sẽ định vị lần lượt các mục. Tiếp theo, nếu tổng chiều cao đã sử dụng thấp hơn chiều cao khung nhìn, thì chân trang sẽ được đặt ở dưới cùng:
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() } } }
Hãy cân nhắc việc thêm contentType
Bắt đầu bằng Compose 1.2, để tăng tối đa hiệu suất của bố cục Lazy, hãy cân nhắc thêm contentType
vào danh sách hoặc lưới của bạn. Điều này cho phép bạn chỉ định loại nội dung cho mỗi mục của bố cục, trong trường hợp bạn đang soạn danh sách hoặc lưới bao gồm nhiều loại mục khác nhau:
LazyColumn { items(elements, contentType = { it.type }) { // ... } }
Khi bạn cung cấp contentType
, Compose chỉ có thể sử dụng lại thành phần giữa các mục cùng loại. Vì việc tái sử dụng sẽ hiệu quả hơn khi bạn tạo các mục có cấu trúc tương tự nhau, bạn nên cung cấp loại nội dung nhằm đảm bảo Compose không cố soạn một mục loại A ở đầu một mục hoàn toàn khác loại B. Điều này giúp tối đa hoá lợi ích của việc sử dụng lại thành phần cũng như hiệu suất bố cục Lazy của bạn.
Đo lường hiệu suất
Bạn chỉ có thể đo lường hiệu suất của bố cục Lazy khi chạy ở chế độ phát hành và bật tính năng tối ưu hoá R8. Trên các bản dựng gỡ lỗi, thao tác cuộn bố cục Lazy có thể xuất hiện chậm hơn. Để biết thêm thông tin chi tiết về vấn đề này, hãy đọc bài viết Hiệu suất của Compose.
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Di chuyển
RecyclerView
sang danh sách Lazy - Lưu trạng thái giao diện người dùng trong Compose
- Kotlin cho Jetpack Compose