← All courses

Lists & Scrolling

🗓 May 31, 2026 ⏱ 2 min read

ListView for scrolling content

ListView displays a scrollable column of widgets. For a few fixed items you can list children directly; for long or dynamic lists, use ListView.builder, which only builds the items currently on screen (efficient for thousands of rows).

// simple, fixed list
ListView(
  children: const [
    ListTile(title: Text('One')),
    ListTile(title: Text('Two')),
  ],
)

ListView.builder (the efficient way)

ListView.builder(
  itemCount: users.length,
  itemBuilder: (context, index) {
    final user = users[index];
    return ListTile(
      leading: const Icon(Icons.person),
      title: Text(user.name),
      subtitle: Text(user.email),
      onTap: () { /* open profile */ },
    );
  },
)

itemBuilder is called only for visible rows and reused as you scroll — this is what keeps long lists fast.

ListTile: ready-made rows

ListTile gives you a standard row with a leading icon, title, subtitle and trailing widget — perfect for settings and contact lists without building the layout yourself.

Separators and pull-to-refresh

ListView.separated(
  itemCount: users.length,
  separatorBuilder: (_, __) => const Divider(),
  itemBuilder: (_, i) => ListTile(title: Text(users[i].name)),
)

RefreshIndicator(
  onRefresh: () async => await reload(),   // pull-to-refresh
  child: ListView.builder( /* ... */ ),
)

Grids

GridView.builder(
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2, mainAxisSpacing: 8, crossAxisSpacing: 8,
  ),
  itemCount: photos.length,
  itemBuilder: (_, i) => PhotoCard(photos[i]),
)

A note on overflow

If you put a Column with many children on a small screen, it can overflow. Wrap it in a SingleChildScrollView (for a fixed set) or use a ListView (for dynamic data) so it scrolls instead.

Common mistakes

  • Using a plain ListView(children: [...]) for huge lists instead of .builder.
  • Putting a ListView inside a Column without giving it a bounded height (use Expanded).
  • Forgetting that itemBuilder gives you the index to pick the right data.
Summary: Use ListView.builder for efficient scrolling lists (and GridView.builder for grids), ListTile for standard rows, and RefreshIndicator for pull-to-refresh. Wrap overflowing content so it scrolls.