Lists & Scrolling
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
ListViewinside aColumnwithout giving it a bounded height (useExpanded). - Forgetting that
itemBuildergives you theindexto pick the right data.
Summary: UseListView.builderfor efficient scrolling lists (andGridView.builderfor grids),ListTilefor standard rows, andRefreshIndicatorfor pull-to-refresh. Wrap overflowing content so it scrolls.