LazyColumn trong Jetpack Compose — nó là gì, thuộc tính và cách hoạt động

Tác giả: IT Sectr Đã đăng: 2026-06-29 Thời gian đọc: 11 phút

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 — danh sách dọc Jetpack Compose với tải lười biếng chỉ tạo các phần tử hiển thị và tái sử dụng chúng khi cuộn.
  • items chấp nhận một bộ sưu tập dữ liệu và hàm tạo để tạo các mục danh sách, trong khi item thêm các thành phần đơn lẻ.
  • LazyListState theo dõi vị trí cuộn và cho phép điều khiển danh sách theo chương trình qua animateScrollToItem và scrollToItem.
  • Sticky headers cố định tiêu đề phần ở đầu danh sách khi cuộn bằng stickyHeader.
  • LazyColumn hỗ trợ các loại phần tử khác nhau qua tham số contentType để tối ưu hóa việc tái sử dụng.

LazyColumn trong Jetpack Compose là gì

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.

Chữ ký cơ bản của LazyColumn

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.

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

Tham số LazyColumn: items và item

Khối DSL của LazyColumn cung cấp các hàm itemsitem để 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ó.

Ví dụ với các loại phần tử khác nhau

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.

kotlin
@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 và quản lý cuộn

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.

Ví dụ với cuộn theo chương trình

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à.

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

Tối ưu hóa hiệu suất LazyColumn

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.

Bảng các yếu tố hiệu suất

Yếu tốTác độngKhuyến nghị
Khóa (key)Quan trọngLuô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ìnhSử dụng kích thước cố định khi có thể
Danh sách lồng nhauQuan trọngTránh LazyColumn bên trong LazyColumn — sử dụng LazyVerticalGrid

Sticky headers và phần trong LazyColumn

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.

kotlin
@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

LazyColumn khác gì so với Column trong Compose?

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.

Làm thế nào để thêm dấu phân cách giữa các phần tử LazyColumn?

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.

Làm thế nào để cập nhật LazyColumn khi dữ liệu thay đổi?

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.

Có thể lồng LazyColumn bên trong LazyColumn không?

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.

Làm thế nào để phát hiện LazyColumn đã cuộn đến cuố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

  • LazyColumn — danh sách dọc với tải lười biếng chỉ tạo và tái sử dụng các phần tử trong vùng hiển thị để làm việc hiệu quả với dữ liệu lớn.
  • itemsitem — các hàm DSL để thêm bộ sưu tập dữ liệu và thành phần đơn lẻ vào LazyColumn với hỗ trợ khóa và contentType.
  • LazyListState quản lý vị trí cuộn, cung cấp điều hướng theo chương trình qua animateScrollToItem và scrollToItem trong coroutines.
  • contentTypekey — các công cụ tối ưu hóa hiệu suất chính, giảm tái kết hợp và cải thiện tái sử dụng phần tử.
  • stickyHeader cố định tiêu đề phần ở đầu danh sách, cải thiện điều hướng trong danh sách dài với dữ liệu được nhóm.
  • Arrangement.spacedBy và contentPadding quản lý khoảng cách giữa các phần tử và mép của LazyColumn để tuân thủ Material Design.
  • Đối với danh sách ngang với tải lười biếng, sử dụng LazyRow và cho lưới — LazyVerticalGrid, theo cùng nguyên tắc tải lười biếng.

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.

Thảo luận dự án

Đọc thêm