Jetpack Compose: lists primer
It's been a while since Jetpack Compose is finally in a stable form. Some say that might not be ready for prime time (yet) and not every UI can be implemented using Compose.
Nevertheless, it's the future of Android UI and I think it's more than capable to handle all but few complicated scenarios. As a bonus, you also get a very enjoyable experience when building UIs (instead of being a chore)!
Without further ado, let's have a taste of one of the most basic building blocks of a modern UI: lists. No more RecyclerView.Adapter
or any other adapter. Compose takes away all the complexities of building an efficient list.
Small list
For a simple small list, things are quite simple: use a Column
and the items will stack one after the other.
Keep in mind that the number of items on such a list must be kept small. All the items are drawn on the screen. So potential performance issues might emerge if the list is long.
For instance, if we have a list of tasks that we want to display you can use the following snippet.
@Composable
fun smallList(tasks: List<Task>) {
Column {
tasks.forEach { task ->
Text(task.text)
}
}
}
Large list
For a "real-world" list, where only some items are visible and you need to scroll to view the rest, you can use LazyColumn
. This is the replacement for the verbose RecyclerView.Adapter
of the XML-based Android UI world.
Using this composable, only the visible items will be drawn on the screen. As soon as the list is scrolled, the new items will be drawn on the screen with efficiency (i.e. some views that go out of sight might be reused). But these are behind the screens. All you need to do is provide the items to be drawn.
@Composable
fun largeList(tasks: List<Task>) {
LazyColumn(
contentPadding = // 1.
PaddingValues(horizontal = 16.dp, vertical = 8.dp))
{
items(tasks, // 2.
key = { task -> task.id } // 3.
) { task ->
Text( // 4.
task.text,
Modifier // 5.
.clickable( // 6.
onClick = {
viewModel.onItemClick(task)
},
interactionSource = MutableInteractionSource(),
indication = rememberRipple(bounded = true), // 7.
)
)
}
}
}
- For having some space between each row items.
- Use the
items()
method to provide the rows that we want to display in the list. - By default, each item in the list is using the item position as a unique identifier. This can cause problems when the ordering of the list changes. State of reordered items might be lost. When possible, provide a real unique identifier of the underlying data.
- In this simplified case, each row in the list is represented by a simple
Text
. But here you can have anyComposable
method representing each row. - Use the
Modifier
of the row composable to customize each row. - This is to make the row clickable (and providing what happens when the row is clicked).
- This is for having a "ripple" effect when clicking on a row. Alternatively, you can just provide a theme for the entire app (learn more).
Further reading
This aims to be a quick primer for lists in Compose. But there are some quite cool things you can do easily with LazyColumn
such as sticky headers, reacting, and controlling scroll position.
Notable things you cannot do at the moment are having items animations and drag-and-drop reordering (but hopefully will soon be implemented; some workarounds/hacks/external libraries exist).
Happy coding!