LazyColumn in Jetpack Compose: Build a Scrolling List
Show a fast, scrolling list with LazyColumn. Use a data class, design a list row with Card, and handle taps, with a simple fruit shop example.
Almost every app shows a list: chats, products, songs, contacts. In this part of the Android for Beginners series, you'll learn how to build a list in Jetpack Compose using LazyColumn — a smooth, scrolling list of fruits with prices.
Before you start, make sure you've read Part 6: Buttons, Clicks and State.
Why Not Just Use a Column?
You could put 1,000 items inside a Column. But the phone would create all 1,000 at once — even the ones you can't see. That's slow and wastes memory.
LazyColumn is smarter. It's "lazy" in a good way: it only creates the items that are visible on the screen right now. As you scroll, it creates new ones and throws away old ones. That's why lists with thousands of items still scroll smoothly.
LazyColumn= a scrolling list, top to bottomLazyRow= a scrolling list, left to right
Step 1: Describe Your Data
First, describe what one item looks like. We'll use a data class (you learned about them in Part 4):
data class Fruit(
val name: String,
val emoji: String,
val price: Int
)
Now make a list of fruits:
val fruits = listOf(
Fruit("Mango", "🥭", 120),
Fruit("Banana", "🍌", 60),
Fruit("Apple", "🍎", 250),
Fruit("Watermelon", "🍉", 80),
Fruit("Grapes", "🍇", 300),
Fruit("Pineapple", "🍍", 90),
Fruit("Strawberry", "🍓", 450),
Fruit("Orange", "🍊", 180),
Fruit("Coconut", "🥥", 70),
Fruit("Lemon", "🍋", 40)
)
Put this code outside any function, at the bottom of MainActivity.kt.
Step 2: Design One Row
Now design how one fruit looks on the screen:
@Composable
fun FruitRow(fruit: Fruit, onClick: () -> Unit) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable { onClick() }
) {
Row(
modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(text = fruit.emoji, fontSize = 32.sp)
Spacer(modifier = Modifier.width(16.dp))
Column(modifier = Modifier.weight(1f)) {
Text(text = fruit.name, fontWeight = FontWeight.Bold)
Text(text = "৳${fruit.price} per kg", color = Color.Gray)
}
}
}
}
Cardgives each row a nice rounded box with a shadow..clickable { }makes the whole row tappable.Modifier.weight(1f)means "take all the leftover space".
Step 3: Show the List with LazyColumn
@Composable
fun FruitListScreen(modifier: Modifier = Modifier) {
val context = LocalContext.current
LazyColumn(
modifier = modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
item {
Text(
text = "Fresh Fruits 🛒",
fontSize = 26.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = 8.dp)
)
}
items(fruits, key = { it.name }) { fruit ->
FruitRow(
fruit = fruit,
onClick = {
Toast.makeText(context, "You picked ${fruit.name}", Toast.LENGTH_SHORT).show()
}
)
}
}
}
Show it inside setContent with FruitListScreen(modifier = Modifier.padding(innerPadding)) and press Run. Scroll the list, and tap a fruit to see a small pop-up message (a Toast). 🎉
Let's Understand It
item { ... }adds one single item. We used it for the title.items(fruits) { fruit -> ... }adds one row for every fruit in the list. It's like aforloop made for lists.key = { it.name }gives each row a unique ID. This helps Compose keep scrolling smooth when the list changes.contentPaddingadds space around the whole list.spacedBy(8.dp)adds a gap between rows.LocalContext.currentgives us the context that Android needs to show a Toast.
The Most Common Error
If items(fruits) is red with a confusing error, you're missing this import:
import androidx.compose.foundation.lazy.items
Almost every beginner hits this one. Now you know!
Try It Yourself
- Add 5 more fruits to the list.
- Show a "🔥 Sale" label on fruits cheaper than 100 (hint:
if (fruit.price < 100)). - Make a horizontal list using
LazyRowinstead. - Bonus: Add a search box on top (use the
OutlinedTextFieldfrom Part 6), and filter the list withfruits.filter { it.name.contains(query, ignoreCase = true) }.
Frequently Asked Questions
What is the difference between LazyColumn and RecyclerView? RecyclerView is the older way to build lists with XML. LazyColumn does the same job in Compose, with much less code.
Can I make a grid?
Yes! Use LazyVerticalGrid(columns = GridCells.Fixed(2)) { ... }. It works almost the same way.
Where does real data come from? In real apps, lists usually come from the internet (using a library like Retrofit) or a local database (Room). For now, a hard-coded list is perfect for learning.
Quick Recap
LazyColumnonly creates what's visible, so it's fast.items(list) { ... }shows one row per item.- A
data classdescribes what one item holds. .clickablemakes rows tappable.
Our app has a list, but what happens when you tap a fruit? It should open a details page! Let's learn that in the final part: Part 8: Navigation Between Screens.