Overview
Hello Android Devs Greetings of the day,
As we know for listing data in android we have been using ListView or mostly RecyclerViews. But making a RecyclerView is time-consuming and it takes hell of a lot of code.
Now Jetpack compose is here to rescue developers by making it easy to display a list of data. And jetpack compose is also stable now so it is production-ready.
As we know for making RecyclerView we need to create layout files, Adapters, ViewHolders but in Compose it does not require that much code.
Different Control for Making List
To Display a List of data, we can use Column, Row, LazyColumn, LazyRow. These are the available controls in compose.
Column And Row
As we know in XML layout we used to have ListView which is used for the list of data and now in Compose, we have Column and Row for the same.
Column : Column is control where we can arrange our data in a vertical manner. The column takes several parameters in which we have one parameter which is Modifier. The modifier is a class that is used for formatting the field and layout. But we are looking to make the column Scrollable. So Modifier has one method which is verticleScroll() which takes a scrollable state. We can get a scrollable state from a method called remeberScrollState().
@Composable fun SimpleColumnList() { Column( modifier = Modifier.verticalScroll(rememberScrollState()) ) { for (i in 1..10) ListItem(text = "Item $i", modifier = Modifier.padding(8.dp)) } }
Output:
Row : Row is a control where we can arrange our data in a horizontal manner. And as we saw in the Column we can do the same thing with the Row with Modifier with horizontalScroll().
@Composable fun SimpleRowList() { Row( modifier = Modifier .horizontalScroll(rememberScrollState()) ) { for (i in 1..10) ListItem(pos = i) } }
Output :
Row and Column are like ListView. They do not load data in a Lazy manner like RecyclerView. For this scenario, LazyColumn and LazyRow come into the picture.
LazyColumn, LazyRow & LazyVerticleGrid
Jetpack Compose provides LazyColumn, LazyRow, and LazyVerticleGrid in replacement of RecyclerView. These are too easy to implement & lightweight in comparison to RecyclerView.
LazyColumn
LazyColumn is a Composable function. With the help of LazyColumn, we can make a Vertical List which will load lazily.
@Composable fun LazyColumn( modifier: Modifier = Modifier, state: LazyListState = rememberLazyListState(), contentPadding: PaddingValues = PaddingValues(0.dp), reverseLayout: Boolean = false, verticalArrangement: Arrangement.Vertical = if (!reverseLayout) Arrangement.Top else Arrangement.Bottom, horizontalAlignment: Alignment.Horizontal = Alignment.Start, flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), content: LazyListScope.() -> Unit )
- Modifier: Modifier is a class that provides formatting attributes.
- State: State in LazyList provides state of a list like a scroll position, firstVisibleItemIndex so on and so forth.
- ContentPadding: It is a padding that applies to the first and last item in the list.
- ReverseLayout: ReverseLayout attribute is used when we have to display the list in reverse order and it also loads the list in reverse order.
- VerticalArrangement: Arrangement is a class that provides a variety of methods and attributes for Vertical Arrangement like Arrangement.Top, Arrangement.spacedBy(), etc..
- HorizontalAlignment: Alignment is used to align the list in a horizontal manner like center, start, end.
- FlingBehavior: logic describing fling behavior.
- Content: This is Kotlin DSL for LazyListScope which provides the content to be shown in the list.
- LazyListScope: It is Interface that contains methods like item{} for a single item, items(count) for multiple items, itemsIndexed for item with an index number, stickeyHeader etc.
@OptIn(ExperimentalFoundationApi::class) @Composable fun ListColumn() { LazyColumn( modifier = Modifier.fillMaxWidth(), contentPadding = PaddingValues(vertical = 8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), horizontalAlignment = Alignment.CenterHorizontally ) { stickyHeader { Text( text = "Sticky Header", modifier = Modifier .fillMaxWidth() .height(22.dp) .background(Color.Gray), textAlign = TextAlign.Center ) } item { ListItem(text = "First Item") } itemsIndexed(items = (1..10).toList()) { pos, _ -> ListItem("Item $pos") } item { ListItem(text = "Last Item") } } }
Output:
LazyRow
LazyRow is a Composable function. With help of LazyRow, we can make a Horizontal List that will load lazily.
@Composable fun LazyRow( modifier: Modifier = Modifier, state: LazyListState = rememberLazyListState(), contentPadding: PaddingValues = PaddingValues(0.dp), reverseLayout: Boolean = false, horizontalArrangement: Arrangement.Horizontal = if (!reverseLayout) Arrangement.Start else Arrangement.End, verticalAlignment: Alignment.Vertical = Alignment.Top, flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), content: LazyListScope.() -> Unit )
- Modifier: Modifier is a class that provides formatting attributes.
- State: State in LazyList provides state of a list like a scroll position, firstVisibleItemIndex so on and so forth.
- ContentPadding: It is a padding that applies to the first and last item in the list.
- ReverseLayout: ReverseLayout attribute is used when we have to display the list in reverse order and it also loads the list in reverse order.
- HorizontalArrangement: Arrangement is a class that provides a variety of methods and attributes for Vertical Arrangement like Arrangement.Top, Arrangement.spacedBy(), etc..
- VerticalAlignment: Alignment is used to align the list in a Vertical manner like center, start, end.
- FlingBehavior: logic Describing fling behavior.
- Content: This is Kotlin DSL for LazyListScope which provides the content to be shown in the list.
LazyListScope: It is an Interface that contains methods like item{} for a single item, items(count) for multiple items, itemsIndexed for item with index number, etc.
@OptIn(ExperimentalFoundationApi::class) @Composable fun ListRow() { LazyRow( contentPadding = PaddingValues(horizontal = 8.dp, vertical = 8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.Top ) { item { ListItem(text = "First Item") } itemsIndexed(items = (1..10).toList()) { pos, _ -> ListItem("Item $pos") } item { ListItem(text = "Last Item") } } }
Output:
LazyVerticalGrid
As we have been using GridLayoutManager for grids in RecyclerView. Similarly, compose provides LazyVerticalGrid for Grid Layout. As I am writing a blog it is an Experimental Api but we hope it’ll be stable soon.
@ExperimentalFoundationApi @Composable fun LazyVerticalGrid( cells: GridCells, modifier: Modifier = Modifier, state: LazyListState = rememberLazyListState(), contentPadding: PaddingValues = PaddingValues(0.dp), content: LazyGridScope.() -> Unit )
- Cells: GridCells is a sealed class that contains two classes Fixed and Adaptive
- GridCells.Fixed(count) provides a fixed number of cells in Grid.
- GridCells.Adaptive(minSize) adapts size by itself just we need to pass the min size of the grid cell. It’ll try to position as many rows or columns as possible on the condition that every cell has at least “min size” space and all extra space distributed evenly.
- Modifier: Modifier is a class that provides formatting attributes.
- State: State in LazyList provides state of a list like a scroll position, firstVisibleItemIndex so on and so forth.
- ContentPadding: It is a padding that applies to the first and last item in the list.
- Content: LazyGridScope content for LazyGridVerticalGrid.
@OptIn(ExperimentalFoundationApi::class) @Composable fun LazyGrid() { LazyVerticalGrid( cells = GridCells.Adaptive(120.dp), ) { item { ListItem(text = "First Item", Modifier.padding(8.dp)) } itemsIndexed(items = (1..30).toList()) { index, _ -> ListItem(text = "Item $index", Modifier.padding(8.dp)) } item { ListItem(text = "Last Item", Modifier.padding(8.dp)) } } }
Output:
Things made easy with Lazy Layouts
- The thing I like about Lazy Layout is we can add a single independent item but not in the case of our greedy XML layouts. To achieve this kind of behaviour we need to do a lot of work and it is time-consuming.
- Pagination made easy in lazy composable we can use itemsIndexed() lambda function to get visible item indexed and if the index is at last item we can invoke pagination function to load more data from the data source.
- We can use LazyRow inside LazyColumn vise versa. Don’t need nested adapters to achieve this kind of behaviour.
- Compose is written in Kotlin language so we can take full advantage of it. We can make a conditional statement in any composable function.
Conclusion
As in conclusion, I have a little exercise for readers. Let’s think about how we can implement the above output traditionally in RecyclerView, and then try to implement the same behaviour in compose. You’ll understand the difference between RecyclerView and List. Happy Composing.