Jetpack Compose, Android’s modern UI toolkit, simplifies UI development with its declarative approach. One of the essential composables for creating scrollable content is the LazyRow
. It is specifically designed to efficiently display a large number of items in a horizontal list. Understanding how to use LazyRow
is crucial for building performant and user-friendly UIs.
What is LazyRow
in Jetpack Compose?
LazyRow
is a composable function in Jetpack Compose that displays a horizontally scrolling list of items. It is “lazy” because it only composes and lays out the items that are currently visible on the screen (or about to become visible). This lazy behavior is highly efficient when dealing with large datasets, as it minimizes resource usage and improves performance compared to traditional scrolling containers that render all items at once.
Why Use LazyRow
?
- Performance: Only visible items are composed and laid out, significantly improving performance for large datasets.
- Memory Efficiency: Reduces memory footprint as only a subset of items are kept in memory.
- Simplicity: Easy to implement and integrate into your Compose UI.
How to Implement LazyRow
Step 1: Add Dependencies
Make sure you have the necessary dependencies in your build.gradle
file:
dependencies {
implementation("androidx.compose.ui:ui:1.6.0")
implementation("androidx.compose.material:material:1.6.0")
implementation("androidx.compose.foundation:foundation:1.6.0") // Required for LazyRow
implementation("androidx.compose.runtime:runtime:1.6.0")
implementation("androidx.activity:activity-compose:1.8.2") // Required for Compose interoperability with Activities
}
Replace 1.6.0
(or 1.8.2
for activity-compose) with the latest stable version as necessary.
Step 2: Basic Implementation
A simple implementation of LazyRow
to display a list of text items:
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun SimpleLazyRow() {
val items = List(20) { "Item $it" }
LazyRow(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(items) { item ->
Card {
Text(
text = item,
modifier = Modifier.padding(16.dp)
)
}
}
}
}
Explanation:
- A list of 20 items is created.
LazyRow
is used to display the items horizontally.contentPadding
adds padding around the row.horizontalArrangement
specifies spacing between items.items(items)
iterates through the list and renders each item.
Step 3: Custom Item Content
You can customize the item content within the LazyRow
. For instance, display images with text:
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
data class ItemData(val id: Int, val text: String, val imageResId: Int)
@Composable
fun CustomItemLazyRow() {
val items = listOf(
ItemData(1, "Item 1", android.R.drawable.ic_menu_camera),
ItemData(2, "Item 2", android.R.drawable.ic_menu_gallery),
ItemData(3, "Item 3", android.R.drawable.ic_menu_manage)
)
LazyRow(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(items) { item ->
Card {
Column(
modifier = Modifier.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = item.imageResId),
contentDescription = null, // Provide a proper content description
modifier = Modifier.size(48.dp)
)
Spacer(modifier = Modifier.height(4.dp))
Text(text = item.text)
}
}
}
}
}
Key improvements and explanations:
- A data class
ItemData
is introduced to hold the item’s ID, text, and image resource ID. - An
Image
composable is used to display the images. Note the use of `android.R.drawable.ic_menu_camera`, etc as examples, remember to use appropriate drawables from your own resources. Add proper content descriptions to the Image. - Items are displayed in a
Column
for vertical arrangement within each card.
Step 4: Handling Click Events
Add click event handling to the items within the LazyRow
:
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.tooling.preview.Preview
data class ItemData(val id: Int, val text: String, val imageResId: Int)
@Composable
fun ClickableItemLazyRow(onItemClick: (ItemData) -> Unit) {
val items = listOf(
ItemData(1, "Item 1", android.R.drawable.ic_menu_camera),
ItemData(2, "Item 2", android.R.drawable.ic_menu_gallery),
ItemData(3, "Item 3", android.R.drawable.ic_menu_manage)
)
LazyRow(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(items) { item ->
Card(
modifier = Modifier.clickable { onItemClick(item) }
) {
Column(
modifier = Modifier.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = item.imageResId),
contentDescription = null, // Always add proper content descriptions
modifier = Modifier.size(48.dp)
)
Spacer(modifier = Modifier.height(4.dp))
Text(text = item.text)
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun ClickableItemLazyRowPreview() {
ClickableItemLazyRow(onItemClick = { item ->
println("Clicked item: ${item.text}")
})
}
In this example:
- The
clickable
modifier is used to make each card clickable. - An
onItemClick
lambda function is passed as a parameter, allowing the caller to handle the click event. - When an item is clicked, the
onItemClick
function is invoked with the correspondingItemData
.
Step 5: Adding a Key to Items
When dealing with dynamic lists where items may be added, removed, or reordered, providing a key to each item in the LazyRow
can greatly improve performance. The key should be a unique identifier for each item that remains consistent across recompositions. Use the `key` parameter inside the `items` block.
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.tooling.preview.Preview
data class ItemData(val id: Int, val text: String)
@Composable
fun KeyedLazyRow() {
val items = listOf(
ItemData(1, "Item 1"),
ItemData(2, "Item 2"),
ItemData(3, "Item 3")
)
LazyRow(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(
items = items,
key = { item -> item.id }
) { item ->
Card {
Text(
text = item.text,
modifier = Modifier.padding(16.dp)
)
}
}
}
}
@Preview(showBackground = true)
@Composable
fun KeyedLazyRowPreview() {
KeyedLazyRow()
}
In this example, each ItemData
has an id
field, which is used as the key in the items
block:
- Using the
key
parameter optimizes the recomposition process by helping Compose identify which items have changed. - Without a key, Compose may have to recompose all items whenever the list changes, leading to performance issues.
Conclusion
LazyRow
is a powerful and efficient way to display horizontal lists in Jetpack Compose. By leveraging its lazy composition, you can create performant UIs that handle large datasets with ease. Incorporating customizations such as custom item layouts, click handling, and item keys further enhances the flexibility and efficiency of your Compose applications. Whether displaying simple text lists or complex UI elements, LazyRow
is an indispensable tool for modern Android UI development.