LazyColumn là một hàm composable trong Jetpack Compose để tạo danh sách dọc với tải lười biếng các phần tử. Không giống như Column, LazyColumn chỉ tạo và kết hợp các phần tử hiển thị trên màn hình, tái sử dụng chúng khi cuộn. Theo Google Android Documentation, 2025, LazyColumn là công cụ chính để hiển thị tập dữ liệu lớn trong ứng dụng di động nhờ quản lý bộ nhớ hiệu quả.
Những điểm chính
LazyColumn là một hàm composable triển khai danh sách dọc có thể cuộn với tải lười biếng. Không giống như Column hiển thị tất cả các phần tử con cùng một lúc, LazyColumn chỉ tạo các phần tử nằm trong vùng hiển thị.
Cơ chế tải lười biếng trong LazyColumn dựa trên việc tái sử dụng phần tử: khi một phần tử bị ẩn trong khi cuộn, thành phần và bố cục của nó có thể được tái sử dụng cho một phần tử mới được hiển thị. Điều này tiết kiệm bộ nhớ và thời gian CPU, đặc biệt trên các danh sách dài.
Theo Android Developers Blog, 2024, LazyColumn có thể xử lý hiệu quả các danh sách hàng chục nghìn phần tử mà không làm giảm hiệu suất đáng kể. Mỗi phần tử trong LazyColumn có một khóa (key) giúp Compose xác định và giữ nguyên trạng thái của phần tử khi danh sách thay đổi.
LazyColumn chấp nhận các tham số modifier, state, contentPadding, reverseLayout, verticalArrangement và horizontalAlignment. Nội dung được định nghĩa trong khối lambda qua các hàm DSL items và item.
@Composable
fun SimpleLazyColumn() {
val itemsList = (1..100).toList()
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(16.dp)
) {
items(itemsList) { item ->
Text(text = "Mục $item")
}
}
}
Khối DSL của LazyColumn cung cấp các hàm items và item để thêm nội dung. items chấp nhận một bộ sưu tập dữ liệu, khóa và hàm tạo để tạo các phần tử. item thêm một phần tử tĩnh đơn lẻ vào danh sách.
itemsIndexed là một biến thể của items truyền chỉ mục phần tử ngoài dữ liệu. Điều này hữu ích khi bạn cần biết vị trí phần tử mà không cần tính toán riêng. items(size) chỉ chấp nhận số lượng phần tử và hàm tạo mà không gắn với bộ sưu tập.
Tham số key trong items xác định duy nhất mỗi phần tử. Theo Material Design Guidelines, 2025, các khóa cải thiện hiệu suất khi cập nhật và tạo hoạt ảnh cho các phần tử vì Compose có thể theo dõi chuyển động hoặc thay đổi của một phần tử cụ thể bằng khóa của nó.
Hàm items với contentType cho phép LazyColumn tối ưu hóa việc tái sử dụng các phần tử thuộc các loại khác nhau. Trong ví dụ dưới đây, tiêu đề phần và các hàng thông thường được sử dụng trong một danh sách.
@Composable
fun MixedItemsList() {
LazyColumn {
item {
Text(
text = "Tiêu đề",
style = MaterialTheme.typography.headlineMedium
)
}
items(
items = (1..20).toList(),
key = { it },
contentType = { "item" }
) { item ->
Text(text = "Hàng $item")
}
}
}
LazyListState là đối tượng trạng thái của LazyColumn theo dõi vị trí cuộn hiện tại, phần tử hiển thị đầu tiên và độ lệch. Nó có thể được tạo qua rememberLazyListState() và truyền vào tham số state của LazyColumn.
LazyListState cung cấp các phương thức animateScrollToItem và scrollToItem để cuộn theo chương trình đến một phần tử cụ thể. animateScrollToItem tạo hoạt ảnh cuộn mượt mà, trong khi scrollToItem cuộn ngay lập tức. Cả hai phương thức đều yêu cầu gọi bên trong một coroutine trong CompositionContext.
Theo Android Developers, 2024, LazyListState cũng chứa layoutInfo cung cấp thông tin về các phần tử hiển thị — chỉ mục, độ lệch và kích thước của chúng. Điều này hữu ích cho việc triển khai phân tích, theo dõi lượt xem hoặc cuộn vô hạn.
Trong ví dụ này, LazyColumn được điều khiển qua LazyListState. Một nút cuộn danh sách đến phần tử có chỉ mục 50 với hoạt ảnh mượt mà.
@Composable
fun ScrollableList() {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
Column {
Button(
onClick = {
scope.launch {
listState.animateScrollToItem(50)
}
}
) {
Text("Cuộn đến 50")
}
LazyColumn(state = listState) {
items((1..100).toList()) { item ->
Text(
text = "Mục $item",
modifier = Modifier.padding(8.dp)
)
}
}
}
}
Yếu tố hiệu suất chính của LazyColumn là sử dụng khóa đúng cách. Mỗi phần tử nên có một khóa ổn định duy nhất qua tham số key. Không có khóa, Compose không thể tái sử dụng các phần tử một cách chính xác khi dữ liệu thay đổi, dẫn đến việc tái kết hợp.
contentType cho LazyColumn biết phần tử nào có cùng loại bố cục. Khi hai phần tử có cùng contentType vào bể tái chế, LazyColumn có thể tái sử dụng bố cục của chúng mà không cần tái kết hợp. Theo Android Developers Blog, 2024, contentType cải thiện hiệu suất 30–50% trong danh sách có các loại phần tử khác nhau.
Đối với LazyColumn, cũng quan trọng là tránh các tham số không ổn định trong hàm tạo. Mỗi khi tham số phần tử thay đổi, Compose sẽ tái kết hợp phần tử đó. Sử dụng remember và derivedStateOf cho các giá trị ổn định làm giảm số lần tái kết hợp.
| Yếu tố | Tác động | Khuyến nghị |
|---|---|---|
| Khóa (key) | Quan trọng | Luôn đặt khóa ổn định duy nhất cho items |
| contentType | Đáng kể | Chỉ định loại phần tử để tối ưu hóa tái sử dụng |
| Kích thước phần tử | Trung bình | Sử dụng kích thước cố định khi có thể |
| Danh sách lồng nhau | Quan trọng | Tránh LazyColumn bên trong LazyColumn — sử dụng LazyVerticalGrid |
stickyHeader là hàm DSL của LazyColumn cố định tiêu đề phần ở đầu danh sách khi cuộn. Khi phần tiếp theo đến đầu, tiêu đề của nó thay thế tiêu đề hiện tại. Hành vi này quen thuộc với người dùng từ danh sách liên lạc và lịch.
stickyHeader chấp nhận khóa và hàm tạo, tương tự như item. Không giống như item thông thường, stickyHeader vẫn hiển thị khi cuộn qua nội dung của phần của nó. Khi một phần được cuộn hoàn toàn, tiêu đề của phần tiếp theo đẩy tiêu đề trước đó ra ngoài.
Theo Material Design Guidelines, 2025, sticky headers cải thiện điều hướng trong danh sách dài và giảm tải nhận thức cho người dùng. Để triển khai sticky header, chỉ cần bọc tiêu đề phần trong stickyHeader ở đúng vị trí so với các phần tử items.
@Composable
fun SectionedList(sections: Map<String, List<String>>) {
LazyColumn {
sections.forEach { (header, items) ->
stickyHeader {
Text(
text = header,
modifier = Modifier.background(Color.White)
.padding(16.dp)
)
}
items(items) { item ->
Text(text = item, modifier = Modifier.padding(8.dp))
}
}
}
}
Câu hỏi thường gặp
Column hiển thị tất cả các phần tử cùng một lúc và phù hợp cho danh sách tối đa 20–30 phần tử. LazyColumn chỉ tạo các phần tử hiển thị và tái sử dụng chúng khi cuộn, cho phép bạn làm việc với hàng nghìn phần tử mà không mất hiệu suất.
Sử dụng Arrangement.spacedBy trong tham số verticalArrangement hoặc các hàm items với dấu phân cách qua chỉ mục. Đối với dấu phân cách phức tạp, thêm một item riêng với Divider() giữa các phần tử danh sách.
LazyColumn tự động tái kết hợp khi bộ sưu tập dữ liệu thay đổi, nếu sử dụng khóa ổn định. Các thay đổi dữ liệu được phát hiện qua mutableStateListOf hoặc StateFlow khiến chỉ các phần tử thay đổi được vẽ lại.
Không nên lồng trực tiếp LazyColumn bên trong LazyColumn — cả hai đều có cuộn độc lập, tạo ra xung đột cử chỉ. Thay vào đó, hãy sử dụng Column thông thường với LazyColumn bên trong Section có thể cuộn hoặc LazyVerticalGrid cho lưới.
Sử dụng LazyListState.layoutInfo.visibleItemsInfo và so sánh chỉ mục của phần tử hiển thị cuối cùng với tổng số phần tử. Đối với cuộn vô hạn, theo dõi khi phần tử hiển thị cuối cùng đến gần cuối danh sách.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm