Jetpack Compose LazyRow

Jetpack Compose LazyRow is a composable function in Jetpack Compose that creates a horizontally scrollable list. Unlike traditional RecyclerView implementations, Jetpack Compose LazyRow only composes and lays out the items that are visible in the viewport, making it highly efficient for long lists. The Jetpack Compose LazyRow component is part of the androidx.compose.foundation.lazy package and follows the declarative UI paradigm of Jetpack Compose.

Core Properties of Jetpack Compose LazyRow

State Management in Jetpack Compose LazyRow

Jetpack Compose LazyRow efficiently manages state changes and recompositions. Here's a simple example of how state works with LazyRow:

val items = remember { mutableStateOf(listOf("Item 1", "Item 2", "Item 3")) }  
  
LazyRow {  
    items(items.value) { item ->  
        Text(text = item, modifier = Modifier.padding(8.dp))  
    }  
}  

In this example, whenever the items state changes, only the affected items in the Jetpack Compose LazyRow will be recomposed, not the entire list.

Content Padding in Jetpack Compose LazyRow

You can add padding around the content of your Jetpack Compose LazyRow using the contentPadding parameter:

LazyRow(  
    contentPadding = PaddingValues(  
        start = 16.dp,  
        top = 8.dp,  
        end = 16.dp,  
        bottom = 8.dp  
    )  
) {  
    // Items here  
}  

This adds padding around the entire content of the Jetpack Compose LazyRow, which is particularly useful for ensuring items aren't clipped at the edges of the screen.

Horizontal Arrangement in Jetpack Compose LazyRow

The horizontalArrangement parameter allows you to control how items are spaced within the Jetpack Compose LazyRow:

LazyRow(  
    horizontalArrangement = Arrangement.spacedBy(8.dp)  
) {  
    // Items here  
}  

Other arrangement options include Arrangement.Start, Arrangement.End, Arrangement.Center, and Arrangement.SpaceBetween, giving you fine-grained control over item positioning in your Jetpack Compose LazyRow.

Content Types in Jetpack Compose LazyRow

For lists with multiple item types, Jetpack Compose LazyRow provides support through content types:

LazyRow {  
    itemsIndexed(  
        items = mixedItems,  
        contentType = { _, item ->   
            when(item) {  
                is TextItem -> "text"  
                is ImageItem -> "image"  
            }  
        }  
    ) { index, item ->  
        when(item) {  
            is TextItem -> Text(text = item.text)  
            is ImageItem -> Image(  
                painter = painterResource(id = item.resId),  
                contentDescription = null  
            )  
        }  
    }  
}  

This optimization helps Jetpack Compose LazyRow to better reuse composables of the same type, improving performance.

Advanced Features of Jetpack Compose LazyRow

Item Animations in Jetpack Compose LazyRow

Jetpack Compose LazyRow supports animations when items are added, removed, or reordered:

LazyRow(  
    modifier = Modifier.animateItemPlacement(  
        animationSpec = spring(  
            dampingRatio = Spring.DampingRatioMediumBouncy,  
            stiffness = Spring.StiffnessLow  
        )  
    )  
) {  
    // Items here  
}  

This creates a smooth animation effect when the items in your Jetpack Compose LazyRow change position.

Sticky Headers in Jetpack Compose LazyRow

Although less common in horizontal lists, Jetpack Compose LazyRow supports sticky headers:

LazyRow {  
    stickyHeader {  
        Text(  
            text = "Sticky Header",  
            modifier = Modifier  
                .background(MaterialTheme.colorScheme.primary)  
                .padding(16.dp)  
                .fillMaxHeight(),  
            color = MaterialTheme.colorScheme.onPrimary  
        )  
    }  
      
    items(50) { index ->  
        Text(  
            text = "Item $index",  
            modifier = Modifier.padding(16.dp)  
        )  
    }  
}  

This keeps the header visible at the start of the Jetpack Compose LazyRow as the user scrolls through the content.

Lazy Loading and Pagination in Jetpack Compose LazyRow

Implementing infinite scrolling or pagination with Jetpack Compose LazyRow is straightforward:

LazyRow {  
    items(currentItems) { item ->  
        ItemCard(item)  
    }  
      
    item {  
        if (isLoading) {  
            CircularProgressIndicator(  
                modifier = Modifier.padding(16.dp)  
            )  
        } else if (hasMoreItems) {  
            Button(  
                onClick = { loadMoreItems() },  
                modifier = Modifier.padding(16.dp)  
            ) {  
                Text("Load More")  
            }  
        }  
    }  
}  

This approach allows your Jetpack Compose LazyRow to load more items as the user reaches the end of the list.

Complete Example of Jetpack Compose LazyRow

Let's put everything together in a full example that demonstrates key features of Jetpack Compose LazyRow:

import androidx.compose.foundation.Image  
import androidx.compose.foundation.background  
import androidx.compose.foundation.layout.*  
import androidx.compose.foundation.lazy.LazyRow  
import androidx.compose.foundation.lazy.items  
import androidx.compose.foundation.shape.RoundedCornerShape  
import androidx.compose.material3.Card  
import androidx.compose.material3.MaterialTheme  
import androidx.compose.material3.Surface  
import androidx.compose.material3.Text  
import androidx.compose.runtime.Composable  
import androidx.compose.ui.Alignment  
import androidx.compose.ui.Modifier  
import androidx.compose.ui.draw.clip  
import androidx.compose.ui.graphics.Color  
import androidx.compose.ui.layout.ContentScale  
import androidx.compose.ui.res.painterResource  
import androidx.compose.ui.text.font.FontWeight  
import androidx.compose.ui.unit.dp  
import androidx.compose.ui.unit.sp  
  
data class Product(  
    val id: Int,  
    val name: String,  
    val price: String,  
    val imageRes: Int  
)  
  
@Composable  
fun ProductScreen() {  
    val products = listOf(  
        Product(1, "Laptop", "$999.99", R.drawable.laptop),  
        Product(2, "Smartphone", "$699.99", R.drawable.smartphone),  
        Product(3, "Headphones", "$149.99", R.drawable.headphones),  
        Product(4, "Tablet", "$349.99", R.drawable.tablet),  
        Product(5, "Smartwatch", "$249.99", R.drawable.smartwatch),  
        Product(6, "Camera", "$599.99", R.drawable.camera)  
    )  
      
    Surface(  
        modifier = Modifier.fillMaxSize(),  
        color = MaterialTheme.colorScheme.background  
    ) {  
        Column(  
            modifier = Modifier.padding(16.dp)  
        ) {  
            Text(  
                text = "Featured Products",  
                fontSize = 24.sp,  
                fontWeight = FontWeight.Bold,  
                modifier = Modifier.padding(bottom = 16.dp)  
            )  
              
            LazyRow(  
                contentPadding = PaddingValues(8.dp),  
                horizontalArrangement = Arrangement.spacedBy(16.dp)  
            ) {  
                items(products) { product ->  
                    ProductCard(product)  
                }  
            }  
        }  
    }  
}  
  
@Composable  
fun ProductCard(product: Product) {  
    Card(  
        modifier = Modifier  
            .width(180.dp)  
            .height(240.dp),  
        shape = RoundedCornerShape(12.dp)  
    ) {  
        Column {  
            Image(  
                painter = painterResource(id = product.imageRes),  
                contentDescription = product.name,  
                modifier = Modifier  
                    .height(120.dp)  
                    .fillMaxWidth()  
                    .clip(RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp)),  
                contentScale = ContentScale.Crop  
            )  
              
            Column(  
                modifier = Modifier  
                    .padding(16.dp)  
                    .fillMaxSize(),  
                verticalArrangement = Arrangement.spacedBy(8.dp)  
            ) {  
                Text(  
                    text = product.name,  
                    fontWeight = FontWeight.Bold,  
                    fontSize = 16.sp  
                )  
                  
                Text(  
                    text = product.price,  
                    color = MaterialTheme.colorScheme.primary,  
                    fontWeight = FontWeight.Medium  
                )  
                  
                Box(  
                    modifier = Modifier  
                        .background(  
                            color = MaterialTheme.colorScheme.primaryContainer,  
                            shape = RoundedCornerShape(4.dp)  
                        )  
                        .padding(horizontal = 8.dp, vertical = 4.dp)  
                ) {  
                    Text(  
                        text = "New",  
                        color = MaterialTheme.colorScheme.onPrimaryContainer,  
                        fontSize = 12.sp  
                    )  
                }  
            }  
        }  
    }  
}  

This comprehensive example showcases a products catalog using Jetpack Compose LazyRow. The code demonstrates content padding, horizontal arrangement, and custom item rendering within the Jetpack Compose LazyRow.

Extending Jetpack Compose LazyRow Functionality

Jetpack Compose LazyRow can be enhanced with various modifiers and composables. For example, you can implement snap scrolling:

val state = rememberLazyListState()  
val snappedItemIndex = remember { mutableStateOf(0) }  
  
LazyRow(  
    state = state,  
    flingBehavior = rememberSnapFlingBehavior(lazyListState = state),  
    modifier = Modifier.fillMaxWidth()  
) {  
    // Items here  
}  
  
LaunchedEffect(state.isScrollInProgress) {  
    if (!state.isScrollInProgress) {  
        snappedItemIndex.value = state.firstVisibleItemIndex  
    }  
}  

This creates a snapping effect as the user scrolls through items in the Jetpack Compose LazyRow, enhancing the user experience.

The Jetpack Compose LazyRow component is an essential tool for Android developers working with horizontal lists in their applications. By leveraging the features and properties discussed in this guide, you can create efficient, responsive, and visually appealing scrollable horizontal lists using Jetpack Compose LazyRow.