SHAKIL.DEV

SHAKIL.DEV

LazyColumn in Jetpack Compose: Build a Scrolling List
← BACK TO TRANSMISSIONS
October 6, 2026

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 bottom
  • LazyRow = 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)
            }
        }
    }
}
  • Card gives 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 a for loop made for lists.
  • key = { it.name } gives each row a unique ID. This helps Compose keep scrolling smooth when the list changes.
  • contentPadding adds space around the whole list.
  • spacedBy(8.dp) adds a gap between rows.
  • LocalContext.current gives 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

  1. Add 5 more fruits to the list.
  2. Show a "🔥 Sale" label on fruits cheaper than 100 (hint: if (fruit.price < 100)).
  3. Make a horizontal list using LazyRow instead.
  4. Bonus: Add a search box on top (use the OutlinedTextField from Part 6), and filter the list with fruits.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

  • LazyColumn only creates what's visible, so it's fast.
  • items(list) { ... } shows one row per item.
  • A data class describes what one item holds.
  • .clickable makes 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.

Next in Android for Beginners →
Jetpack Compose Navigation for Beginners: Move Between Screens