0
0
Android Kotlinmobile~15 mins

LazyRow for horizontal lists in Android Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - LazyRow for horizontal lists
What is it?
LazyRow is a component in Android's Jetpack Compose that shows a horizontal list of items. It only creates the items that are visible on the screen, which saves memory and improves performance. You can scroll left or right to see more items. It is useful for showing things like image galleries or categories in a row.
Why it matters
Without LazyRow, apps would create all list items at once, even those off-screen, which wastes memory and slows down the app. LazyRow solves this by creating items only when needed, making apps faster and smoother. This improves user experience, especially on devices with limited resources.
Where it fits
Before learning LazyRow, you should know basic Jetpack Compose UI building blocks like Composables and Column/Row layouts. After mastering LazyRow, you can learn about LazyColumn for vertical lists and advanced list features like item animations and paging.
Mental Model
Core Idea
LazyRow is like a conveyor belt that only shows and builds the items you see, moving horizontally.
Think of it like...
Imagine a grocery store conveyor belt at checkout. You only see and handle the items currently on the belt, not all items in the store. LazyRow works the same by only creating visible items in a horizontal line.
┌─────────────────────────────┐
│  [Item 1] [Item 2] [Item 3]  │  <-- Visible items
│  [Item 4] [Item 5] [Item 6]  │  <-- Off-screen items
└─────────────────────────────┘
Scroll → shows next items, LazyRow builds them on demand.
Build-Up - 7 Steps
1
FoundationWhat is LazyRow in Compose
🤔
Concept: Introduce LazyRow as a horizontal scrolling list component in Jetpack Compose.
LazyRow is a Composable that displays a list of items horizontally. Unlike a regular Row, it only creates the items currently visible on screen. This helps apps run smoothly by not wasting resources on off-screen items. Example: LazyRow { items(10) { index -> Text("Item $index") } }
Result
You see a horizontal list of 10 text items you can scroll through left and right.
Understanding that LazyRow creates only visible items helps you build efficient horizontal lists without slowing down your app.
2
FoundationBasic usage of LazyRow
🤔
Concept: Learn how to add simple items inside LazyRow using the items() function.
Use LazyRow with items() to display a list. Each item is a Composable you define. Example: val fruits = listOf("Apple", "Banana", "Cherry") LazyRow { items(fruits) { fruit -> Text(fruit) } }
Result
A horizontal list showing 'Apple', 'Banana', and 'Cherry' that you can scroll horizontally.
Knowing how to pass a list to LazyRow and display each item is the foundation for building horizontal lists.
3
IntermediateCustomizing item spacing and padding
🤔Before reading on: do you think LazyRow adds spacing between items automatically or do you need to add it yourself? Commit to your answer.
Concept: Learn how to control space between items and padding inside LazyRow.
LazyRow does not add spacing between items by default. You can add horizontal spacing using the horizontalArrangement parameter. Example: LazyRow( horizontalArrangement = Arrangement.spacedBy(16.dp), contentPadding = PaddingValues(horizontal = 8.dp) ) { items(5) { index -> Box(Modifier.size(50.dp).background(Color.Blue)) } }
Result
A horizontal list with blue boxes spaced 16 dp apart and 8 dp padding on left and right edges.
Knowing how to add spacing and padding lets you create visually pleasing horizontal lists that match your app design.
4
IntermediateHandling item clicks inside LazyRow
🤔Before reading on: do you think you can add click listeners directly inside LazyRow items or do you need a separate component? Commit to your answer.
Concept: Learn how to make items inside LazyRow respond to user taps.
You can add clickable behavior by wrapping item content with Modifier.clickable. Example: LazyRow { items(3) { index -> Text( "Item $index", Modifier .padding(8.dp) .clickable { println("Clicked item $index") } ) } }
Result
Each item in the horizontal list prints a message when tapped.
Understanding how to add click handlers inside LazyRow items enables interactive horizontal lists.
5
IntermediateLazyRow with dynamic data and state
🤔Before reading on: do you think LazyRow automatically updates when the data changes or do you need to manage state yourself? Commit to your answer.
Concept: Learn how to connect LazyRow to dynamic data that can change during app use.
LazyRow reflects changes if the data list is updated in a Compose state. Example: var items by remember { mutableStateOf(listOf("A", "B")) } LazyRow { items(items) { item -> Text(item) } } // Later update items = listOf("A", "B", "C") to show new item.
Result
LazyRow updates to show new items when the data list changes.
Knowing how LazyRow works with Compose state helps you build dynamic, reactive horizontal lists.
6
AdvancedPerformance benefits of LazyRow
🤔Before reading on: do you think LazyRow creates all items at once or only visible ones? Commit to your answer.
Concept: Understand how LazyRow improves app performance by creating only visible items.
LazyRow uses a lazy layout that only composes and lays out items currently visible plus a small buffer. This reduces memory use and CPU work compared to creating all items at once. This is especially important for long lists or complex item layouts.
Result
Apps using LazyRow run smoother and use less memory when showing horizontal lists.
Understanding LazyRow's lazy creation is key to building efficient, scalable UI lists.
7
ExpertLazyRow internals and item recycling
🤔Before reading on: do you think LazyRow recycles item views like RecyclerView or creates new Composables each time? Commit to your answer.
Concept: Explore how LazyRow manages item composition and recycling internally in Compose.
Unlike RecyclerView, LazyRow does not recycle views but reuses Composables by remembering their state and keys. It composes only visible items and disposes off-screen ones. Keys help maintain item identity during scrolling. This approach fits Compose's declarative model and avoids manual recycling complexity.
Result
LazyRow efficiently manages item lifecycle with Compose's state system, balancing performance and simplicity.
Knowing LazyRow's internal difference from RecyclerView helps you debug and optimize complex lists.
Under the Hood
LazyRow works by composing only the items visible in the horizontal viewport plus a small buffer. It uses Compose's slot table to remember item states and keys to track identity. When scrolling, it disposes items that move off-screen and composes new ones entering view. This lazy composition reduces memory and CPU usage compared to creating all items at once.
Why designed this way?
LazyRow was designed to fit Jetpack Compose's declarative UI model, avoiding the imperative view recycling of RecyclerView. This simplifies code and leverages Compose's efficient recomposition and state management. The lazy approach balances performance with ease of use, making horizontal lists smooth and responsive.
┌───────────────┐
│ LazyRow View  │
├───────────────┤
│ Visible Items │◄── Composed and displayed
│ + Buffer      │
├───────────────┤
│ Off-screen    │──► Disposed to save resources
│ Items         │
└───────────────┘

Scroll → triggers compose/dispose cycle

Keys track item identity to preserve state.
Myth Busters - 3 Common Misconceptions
Quick: Does LazyRow create all list items at once or only visible ones? Commit to your answer.
Common Belief:LazyRow creates all items in the list immediately, just like a regular Row.
Tap to reveal reality
Reality:LazyRow only composes and lays out the items currently visible plus a small buffer, not the entire list.
Why it matters:Believing it creates all items leads to inefficient UI design and poor app performance, especially with large lists.
Quick: Can you add vertical scrolling to LazyRow by default? Commit to your answer.
Common Belief:LazyRow supports vertical scrolling because it is a scrollable list.
Tap to reveal reality
Reality:LazyRow only scrolls horizontally. For vertical scrolling, use LazyColumn instead.
Why it matters:Trying to use LazyRow for vertical lists causes layout bugs and poor user experience.
Quick: Does LazyRow recycle item views like RecyclerView? Commit to your answer.
Common Belief:LazyRow recycles views like RecyclerView to improve performance.
Tap to reveal reality
Reality:LazyRow does not recycle views but reuses Composables by remembering state and keys in Compose's declarative model.
Why it matters:Misunderstanding this can cause confusion when debugging item state or performance issues.
Expert Zone
1
LazyRow's item keys are crucial for preserving item state during recomposition and scrolling; missing keys can cause subtle UI bugs.
2
LazyRow does not recycle views but relies on Compose's slot table and state management, which changes how you think about item reuse compared to RecyclerView.
3
Performance tuning LazyRow involves balancing item size, spacing, and buffer size to avoid janky scrolling on complex lists.
When NOT to use
Avoid LazyRow when you need complex item recycling with manual control or very large datasets requiring paging. In such cases, consider RecyclerView with Paging library or Compose's Paging integration for better memory management.
Production Patterns
In production, LazyRow is often combined with state management libraries like ViewModel and LiveData or Flow to display dynamic horizontal lists such as image carousels, category selectors, or story feeds. Developers use keys to maintain item identity and add custom item animations for smooth UX.
Connections
RecyclerView
LazyRow is a Compose alternative to RecyclerView's horizontal list.
Understanding RecyclerView's imperative recycling helps appreciate LazyRow's declarative lazy composition and state management differences.
Paging Library
LazyRow can be combined with paging to load large horizontal lists efficiently.
Knowing how paging works with LazyRow helps build scalable apps that load data on demand.
Conveyor Belt Systems (Industrial Engineering)
LazyRow's lazy loading is like a conveyor belt showing only items currently needed.
Recognizing this pattern in physical systems helps understand efficient resource use in UI design.
Common Pitfalls
#1Creating all items inside LazyRow manually without lazy loading.
Wrong approach:Row { for (i in 0 until 1000) { Text("Item $i") } }
Correct approach:LazyRow { items(1000) { i -> Text("Item $i") } }
Root cause:Confusing Row with LazyRow and not using lazy loading causes performance issues.
#2Not providing stable keys for items causing UI glitches on scroll.
Wrong approach:LazyRow { items(itemsList) { item -> Text(item.name) } }
Correct approach:LazyRow { items(itemsList, key = { it.id }) { item -> Text(item.name) } }
Root cause:Ignoring keys makes Compose lose track of item identity, causing recomposition bugs.
#3Trying to scroll vertically inside LazyRow.
Wrong approach:LazyRow(modifier = Modifier.verticalScroll(rememberScrollState())) { items(10) { Text("Item $it") } }
Correct approach:LazyColumn { items(10) { Text("Item $it") } }
Root cause:Misunderstanding LazyRow's horizontal-only scrolling causes layout and UX errors.
Key Takeaways
LazyRow is a horizontal scrolling list in Jetpack Compose that creates only visible items for better performance.
You control item spacing and padding with parameters like horizontalArrangement and contentPadding.
Adding click listeners inside LazyRow items makes the list interactive and responsive.
LazyRow relies on Compose's declarative model and state management instead of view recycling.
Providing stable keys for items is essential to maintain UI consistency during scrolling and recomposition.