How to Create LazyColumn with Pagination in Android Jetpack Compose
Pagination or infinite scrolling is a popular technique to load large sets of data incrementally as the user scrolls down the application, thereby improving performance and user experience. This blog post guides you through creating a LazyColumn with pagination in Android Jetpack Compose.
Below is the entire code that we will dissect in this post:
@Composable
fun PaginationExample() {
val page = remember { mutableStateOf(1) }
val loading = remember { mutableStateOf(false) }
val itemList = remember { mutableStateListOf<String>() }
val listState = rememberLazyListState()
LazyColumn(
state = listState,
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(itemList) { item ->
Text(text = item, modifier = Modifier.padding(10.dp))
}
item {
if (loading.value) {
Box(modifier = Modifier.fillMaxWidth().padding(10.dp), contentAlignment = Alignment.Center) {
CircularProgressIndicator(modifier = Modifier.size(50.dp), strokeWidth = 2.dp)
}
}
}
}
LaunchedEffect(key1 = page.value) {
loading.value = true
delay(2000) // Simulate a network delay
itemList.addAll(generateFakeData(page.value))
loading.value = false
}
// Observe scroll state to load more items
LaunchedEffect(listState) {
snapshotFlow { listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index }
.collectLatest { index ->
if (!loading.value && index != null && index >= itemList.size - 5) {
page.value++
}
}
}
}
fun generateFakeData(page: Int): List<String> {
return List(20) { "Item ${(page - 1) * 20 + it + 1}" }
}
Now, let’s go step by step:
We begin by initializing the required variables using the remember keyword to maintain the state across recompositions.
val page = remember { mutableStateOf(1) }
val loading = remember { mutableStateOf(false) }
val itemList = remember { mutableStateListOf<String>() }
val listState = rememberLazyListState()
Next, we construct a LazyColumn that takes these items as input. We use Modifier.fillMaxSize() to make it fill all the available space, and Arrangement.spacedBy(10.dp) to add space between the items.
Inside the LazyColumn, we use the items method to loop over our itemList and display each item as a Text composable.
LazyColumn(
state = listState,
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(itemList) { item ->
Text(text = item, modifier = Modifier.padding(10.dp))
}
We also add a loading indicator at the bottom of the list, which will be displayed while new items are being fetched:
item {
if (loading.value) {
Box(modifier = Modifier.fillMaxWidth().padding(10.dp), contentAlignment = Alignment.Center) {
CircularProgressIndicator(modifier = Modifier.size(50.dp), strokeWidth = 2.dp)
}
}
}
}
In the LaunchedEffect block, we simulate a delay to mimic network latency, and then add items to our list.
LaunchedEffect(key1 = page.value) {
loading.value = true
delay(2000) // Simulate a network delay
itemList.addAll(generateFakeData(page.value))
loading.value = false
}
The last part of our Composable is where the infinite scrolling is implemented. We use another LaunchedEffect block to monitor the scroll state of the list. Whenever the last visible item is within the last 5 items of our list, we increment the page number, triggering the loading of more items.
// Observe scroll state to load more items
LaunchedEffect(listState) {
snapshotFlow { listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index }
.collectLatest { index ->
if (!loading.value && index != null && index >= itemList.size - 5) {
page.value++
}
}
}
And we have a function to generate fake data.
fun generateFakeData(page: Int): List<String> {
return List(20) { "Item ${(page - 1) * 20 + it + 1}" }
}
This function takes the current page number as input and generates a list of 20 items. The text of each item is the string “Item” followed by its number. The number is calculated as ((page – 1) * 20) + it + 1 where it is the index of the item in the list (ranging from 0 to 19).
The reason for ((page – 1) * 20) + it + 1 is to generate a unique number for each item across different pages. For example, for page 1, the numbers will range from 1 to 20. For page 2, the numbers will range from 21 to 40, and so on. This way, we ensure that every item across all pages has a unique number.
Please note that in a real-world application, this data would be fetched from an actual data source, like a server or a local database. The generateFakeData function is only for demonstration purposes in this context.
You will get the following output.
And that’s it! You’ve successfully implemented a LazyColumn with pagination in Jetpack Compose. The pagination helps us load and display data incrementally, improving the performance and the user experience.