flutter
/

Flutter ListView Widget Tutorial for Beginners

Last Sync: Today

On this page

10
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

Flutter ListView Widget Tutorial for Beginners

What is ListView in Flutter?

ListView is one of the most commonly used scrolling widgets in Flutter. It displays its children one after another in a scrolling direction (vertical by default). ListView is highly customizable and provides several constructors to suit different needs: the default constructor for a fixed list of children, ListView.builder for dynamic or infinite lists, ListView.separated to insert separators, and ListView.custom for fine‑grained control.

Basic Usage

The simplest way to create a ListView is to provide a fixed list of children. This is perfect when you have a small, known set of items.

DARTRead-only
1
ListView(
  children: [
    ListTile(title: Text('Item 1')),
    ListTile(title: Text('Item 2')),
    ListTile(title: Text('Item 3')),
    // ... more items
  ],
)

When you run this, you'll get a vertically scrolling list of list tiles. By default, ListView scrolls vertically, but you can change that with the scrollDirection property.

ListView.builder: Dynamic Lists

For long or infinite lists, use ListView.builder. It creates children on demand, which improves performance. You provide an itemBuilder function that returns a widget for a given index.

DARTRead-only
1
ListView.builder(
  itemCount: 100,
  itemBuilder: (context, index) {
    return ListTile(
      leading: Icon(Icons.numbers),
      title: Text('Item $index'),
    );
  },
)

The itemCount tells the builder how many items there are. If you omit it, the list will be infinite (useful for data that loads continuously).

ListView.separated: Lists with Separators

When you need dividers between items, ListView.separated is the perfect choice. It takes an itemBuilder and a separatorBuilder.

DARTRead-only
1
ListView.separated(
  itemCount: 20,
  itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
  separatorBuilder: (context, index) => Divider(),
)

Key Properties

ListView offers many properties to control its behavior. Here are the most important ones:

  • children: The list of widgets (for the default constructor).
  • scrollDirection: Axis.horizontal (horizontal scrolling) or Axis.vertical (default).
  • reverse: If true, the list scrolls in the opposite direction (e.g., bottom to top).
  • padding: Adds empty space around the list.
  • physics: Determines how the list responds to scrolling. Common values: AlwaysScrollableScrollPhysics(), BouncingScrollPhysics(), ClampingScrollPhysics(), NeverScrollableScrollPhysics().
  • shrinkWrap: If true, the list will size itself to fit its content (useful inside a Column). Default is false, meaning the list expands to fill its parent.
  • itemExtent: Forces each child to have a fixed extent (height for vertical lists, width for horizontal). This improves performance because the system doesn't need to measure each child.
  • cacheExtent: The area (in pixels) before and after the visible area where items are built ahead of time.

Horizontal ListView

To create a horizontal scrolling list, set scrollDirection to Axis.horizontal.

DARTRead-only
1
ListView(
  scrollDirection: Axis.horizontal,
  children: [
    Container(width: 100, height: 100, color: Colors.red),
    Container(width: 100, height: 100, color: Colors.green),
    Container(width: 100, height: 100, color: Colors.blue),
  ],
)

Don't forget to give the children a width, otherwise they might try to expand horizontally and cause an error.

Using shrinkWrap Inside a Column

A common mistake is placing a ListView inside a Column without setting shrinkWrap: true. Because a ListView normally expands to fill its parent, and a Column doesn't limit its height, you'll get an infinite height error. To fix this, either wrap the ListView with Expanded (so it takes the remaining space) or set shrinkWrap: true (so it takes only as much space as its content).

DARTRead-only
1
Column(
  children: [
    Text('Header'),
    Expanded(                    // ✅ Use Expanded
      child: ListView.builder(
        itemCount: 10,
        itemBuilder: (_, i) => ListTile(title: Text('Item $i')),
      ),
    ),
    Text('Footer'),
  ],
)

// Alternative using shrinkWrap (if you need the list to size itself)
Column(
  children: [
    Text('Header'),
    ListView.builder(
      shrinkWrap: true,          // ✅ shrinkWrap instead of Expanded
      physics: NeverScrollableScrollPhysics(), // often used together
      itemCount: 5,
      itemBuilder: (_, i) => ListTile(title: Text('Item $i')),
    ),
    Text('Footer'),
  ],
)

Common Mistakes Beginners Make

  • Not handling large lists: Using the default ListView constructor with hundreds of items can hurt performance. Always use ListView.builder for long or dynamic lists.
  • Forgetting shrinkWrap inside Column/ListView: Leads to unbounded height errors.
  • Misunderstanding physics: Setting NeverScrollableScrollPhysics() when you want scrolling, or not disabling scrolling when you need a non‑scrollable list.
  • Incorrect itemExtent usage: If children have different sizes, providing a fixed itemExtent can cause clipping or gaps.
  • Nesting ListViews without constraints: Putting a horizontal ListView inside a vertical ListView is fine, but ensure each has a fixed height/width.

Key Points to Remember

  • Use ListView for fixed, small lists; ListView.builder for dynamic or large lists.
  • Set shrinkWrap: true when placing a ListView inside another unbounded container (like Column or another ListView).
  • Adjust scrollDirection for horizontal lists.
  • physics controls the scroll behavior; use NeverScrollableScrollPhysics() to disable scrolling.
  • itemExtent can improve performance if all children have the same size.
  • Use ListView.separated to easily add dividers.

Common Interview Questions

  1. What's the difference between ListView and ListView.builder?
  2. How does shrinkWrap work, and when should you use it?
  3. Explain itemExtent and its performance benefits.
  4. How would you create a horizontally scrolling list of images?
  5. What happens if you put a ListView inside a Column without shrinkWrap or Expanded? How do you fix it?
  6. Describe the use of cacheExtent and how it affects scrolling smoothness.

Try it yourself

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('ListView Example')),
        body: ListView.builder(
          itemCount: 20,
          itemBuilder: (context, index) {
            return ListTile(
              leading: CircleAvatar(
                child: Text('$index'),
              ),
              title: Text('Item $index'),
              subtitle: Text('Description for item $index'),
            );
          },
        ),
      ),
    ),
  );
}

Test Your Knowledge

Q1
of 3

Which ListView constructor is most efficient for a list with 10,000 items?

A
ListView()
B
ListView.builder()
C
ListView.separated()
D
ListView.custom()
Q2
of 3

What does setting `shrinkWrap: true` do in a ListView?

A
Makes the list scroll faster
B
Causes the list to take only the space needed by its children
C
Shrinks each child to a smaller size
D
Prevents the list from scrolling
Q3
of 3

How do you create a horizontal scrolling ListView?

A
Set `scrollDirection: Axis.horizontal`
B
Set `orientation: Horizontal`
C
Use `HorizontalListView()` widget
D
Wrap it with `RotatedBox`

Previous

flutter stack

Next

flutter gridview

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.