ListView.builder in Flutter
Create efficient, dynamic lists with lazy rendering
Download Complete ExamplesWhat is ListView.builder?
The ListView.builder is a ListView constructor that creates elements on demand. It's extremely efficient for long lists because it only renders the visible elements.
ListView Normal
Renders all items at the same time
ListView.builder
Renders only the visible items
Basic Syntax
Basic Constructor of ListView.builder
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
)
Main Features:
- Lazy rendering: Only creates the visible elements
- Efficient with long lists: Ideal for 100+ elements
- Dynamic: Adapts to changes in the data
- Customizable: Full control over each item
Main Parameters
itemCount
Total number of elements in the list
itemCount: myList.length
itemBuilder
Function that builds each element
itemBuilder: (context, index) {
return MyWidget(item[index]);
}
scrollDirection
Scroll direction (vertical/horizontal)
scrollDirection: Axis.vertical
When to use ListView.builder?
Long Lists
Lists with many elements (100+) where performance is crucial
// Lista de 1000 usuarios
ListView.builder(
itemCount: users.length,
itemBuilder: (ctx, i) => UserCard(users[i]),
)
Dynamic Data
Lists that change frequently or load from an API
// Lista de noticias en tiempo real
ListView.builder(
itemCount: news.length,
itemBuilder: (ctx, i) => NewsItem(news[i]),
)
Mobile Apps
Applications that display feeds, chats, or any extensive list
// Feed de redes sociales
ListView.builder(
itemCount: posts.length,
itemBuilder: (ctx, i) => PostCard(posts[i]),
)
Visual Examples
1. Basic List with ListTile
ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Text(users[index].name[0]),
),
title: Text(users[index].name),
subtitle: Text(users[index].email),
trailing: Icon(Icons.chevron_right),
onTap: () => navigateToUser(users[index]),
);
},
)
2. Horizontal List
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.all(8),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20),
),
child: Text(categories[index]),
);
},
)
3. List with Custom Items
ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(products[index].name),
Text('\$${products[index].price}'),
],
),
SizedBox(height: 8),
Text(products[index].description),
SizedBox(height: 8),
Text('★' * products[index].rating),
],
),
),
);
},
)
Properties of the ListView.builder
| Property | Type | Description | Required |
|---|---|---|---|
| itemCount | int | Total number of elements in the list | Optional* |
| itemBuilder | IndexedWidgetBuilder | Function that builds each element | Yes |
| scrollDirection | Axis | Scroll direction (vertical/horizontal) | No |
| padding | EdgeInsets | Space around the list | No |
| physics | ScrollPhysics | Scroll behavior | No |
| shrinkWrap | bool | Whether the list should adjust its size | No |
Note about itemCount:
If itemCount, isn't provided, the list will be infinite. This is useful for lists that load progressively or have an unknown number of elements.
Generator for ListView.builder
// El código se generará aquí
ListView.builder vs Alternatives
| Widget | Advantages | Disadvantages | When to use |
|---|---|---|---|
| ListView.builder | Efficient, lazy loading, dynamic | More complex for simple lists | Long or dynamic lists |
| ListView | Simple, direct | Renders all items | Short, static lists |
| Column | Maximum control, flexible | No automatic scroll, inefficient | Small, fixed number of widgets |
| GridView.builder | Efficient for grids | Additional complexity | Grid/column lists |
Practical Exercises
Exercise 1: Task List
Create a task list where each item shows the title and completion status.
Solution:
ListView.builder(
itemCount: tasks.length,
itemBuilder: (context, index) {
return CheckboxListTile(
title: Text(tasks[index].title),
value: tasks[index].completed,
onChanged: (bool? value) {
setState(() {
tasks[index].completed = value!;
});
},
);
},
)
Exercise 2: Infinite List
Create a list that loads more elements when the user reaches the end.
Solution:
ListView.builder(
itemCount: items.length + 1,
itemBuilder: (context, index) {
if (index == items.length) {
// Mostrar loading al final return Center(child: CircularProgressIndicator());
}
return ListTile(title: Text(items[index]));
},
)
Exercise 3: List with Different Types
Create a list that shows different types of widgets based on the index.
Solution:
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
if (index % 3 == 0) {
return HeaderItem(items[index]);
} else {
return ContentItem(items[index]);
}
},
)
Tips and Best Practices
✅ What you SHOULD do
- Use unique keys for items that can change
- Implement pagination for very long lists
- Use const constructors in itemBuilder when possible
- Consider using ScrollController for advanced control
❌ What you should NOT do
- Don't use setState inside itemBuilder
- Avoid heavy calculations in itemBuilder
- Don't forget itemCount in infinite lists
- Don't use ListView.builder for very short lists
Pro Tip
For extremely long lists, consider using ListView.separated() which lets you define a custom separator between items, improving performance and appearance.