ListView.Builder in Flutter
Create efficient, dynamic, high-performance lists
Download Complete ExamplesWhat is ListView.Builder?
The ListView.Builder widget in Flutter is the most efficient way to create lists with many elements, since it builds widgets on demand as they're needed.
ListView Basics
- ❌ Builds all items at the same time
- ❌ High memory consumption
- ❌ Slow with many elements
- ❌ Not scalable
ListView.Builder
- ✅ Builds items on demand
- ✅ Optimized memory
- ✅ Fast even with thousands of items
- ✅ Highly scalable
Advantages of ListView.Builder:
- ✅ Lazy Loading: Only builds the visible elements
- ✅ High Performance: Ideal for large lists
- ✅ Optimized Memory: Doesn't load all the data at once
- ✅ Dynamic: Easy to update and modify
- ✅ Flexible: Full customization of each item
When to use ListView.Builder?
Large Lists
When you have many elements (50+)
Dynamic Data
When data comes from APIs or databases
Changing Content
When the list can grow or change
High-Performance Apps
When you need to optimize performance
Basic Implementation
Basic ListView.Builder with a list of elements
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ListView.Builder Example',
home: const ListViewExample(),
);
}
}
class ListViewExample extends StatelessWidget {
const ListViewExample({super.key});
// Lista de datos de ejemplo final List items = [
'Manzana', 'Banana', 'Naranja', 'Uva', 'Fresa',
'Piña', 'Mango', 'Pera', 'Kiwi', 'Sandía',
'Melón', 'Durazno', 'Cereza', 'Limón', 'Lima'
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Lista de Frutas'),
backgroundColor: Colors.green,
),
body: ListView.builder(
itemCount: items.length, // Número total de elementos itemBuilder: (context, index) {
// Este builder se llama solo para los items visibles final fruit = items[index];
final color = index % 2 == 0 ? Colors.green[50] : Colors.white;
return Container(
margin: const EdgeInsets.symmetric(vertical: 2, horizontal: 8),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(8),
),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green[100],
child: Text(
'${index + 1}',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
),
title: Text(
fruit,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
subtitle: Text('Fruta número ${index + 1}'),
trailing: const Icon(Icons.chevron_right, color: Colors.green),
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Seleccionaste: $fruit'),
duration: const Duration(seconds: 1),
),
);
},
),
);
},
),
);
}
}
Properties of ListView.Builder
itemCount
Total number of elements in the list
Type: int?
Required: No (but recommended)
Default: null (infinite list)
itemBuilder
Function that builds each element in the list
Type: Widget? Function(BuildContext, int)
Required: Yes
scrollDirection
Scroll direction
Type: Axis
Values: Axis.vertical, Axis.horizontal
Default: Axis.vertical
padding
Internal spacing of the list
Type: EdgeInsets?
Default: null
physics
Physical scroll behavior
Type: ScrollPhysics?
Common values: AlwaysScrollableScrollPhysics(), BouncingScrollPhysics(), NeverScrollableScrollPhysics()
shrinkWrap
Whether the list should adjust to its content
Type: bool
Default: false
Usage: For lists inside a Column
Visual Examples
1. Basic List with Different Styles
ListView.builder(
itemCount: tasks.length,
itemBuilder: (context, index) {
final task = tasks[index];
return AnimatedContainer(
duration: Duration(milliseconds: 300),
margin: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
decoration: BoxDecoration(
color: index % 2 == 0 ? Colors.blue[50] : Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 2,
offset: Offset(0, 1),
),
],
),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue[100],
child: Text('${index + 1}'),
),
title: Text(
task.title,
style: TextStyle(fontWeight: FontWeight.w500),
),
subtitle: Text(task.subtitle),
trailing: Icon(
task.completed ? Icons.check_circle : Icons.radio_button_unchecked,
color: task.completed ? Colors.green : Colors.grey,
),
onTap: () => _toggleTask(index),
),
);
},
)
2. Horizontal List with Cards
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: products.length,
padding: EdgeInsets.all(16),
itemBuilder: (context, index) {
final product = products[index];
return Container(
width: 150,
margin: EdgeInsets.only(right: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 3),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(product.icon, size: 48, color: Colors.blue),
SizedBox(height: 12),
Text(
product.name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
textAlign: TextAlign.center,
),
SizedBox(height: 8),
Text(
'\$${product.price}',
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
],
),
);
},
)
Interactive Demo of ListView.Builder
Demo ListView.Builder
0 items visible
// El código se generará aquí
Best Practices
✅ What you SHOULD do
- Use itemCount for lists with a known size
- Keep itemBuilders simple and efficient
- Use const widgets when possible
- Consider using ListView.separated for dividers
- Optimize images with caching and appropriate size
❌ What you should NOT do
- Don't create complex widgets in the itemBuilder
- Don't use setState inside the itemBuilder
- Don't forget itemCount in large lists
- Don't use ListView.builder for small fixed lists
- Don't load heavy data in the builder
Pro Tip
For extremely large lists (1000+ items), consider using ListView.builder with addAutomaticKeepAlives: false and addRepaintBoundaries: false for maximum performance, but only if you don't need to preserve the items' state.
Exercises to Practice
Exercise 1: Contacts App
Create a contact list with real-time search.
Features: Fast scroll, search, grouping by letter
Exercise 2: News Feed
Implement an infinite feed that loads more content when scrolling.
Features: Infinite scroll, different item types, pull-to-refresh
Exercise 3: Shopping Cart
Create a shopping cart with items that can be modified.
Features: Editable items, dynamic total, animations
Common Troubleshooting
❌ Error: "Vertical viewport was given unbounded height"
Solution: Wrap the ListView in an Expanded or use shrinkWrap: true
// En un ColumnExpanded(
child: ListView.builder(...)
)
// O usar shrinkWrapListView.builder(
shrinkWrap: true,
...
)
❌ The list doesn't update when the data changes
Solution: Make sure to call setState() when modifying the list
void _addItem() {
setState(() {
items.add(newItem);
});
}
❌ Slow scroll with complex items
Solution: Optimize the itemBuilder and use const widgets
// Usar const widgetsitemBuilder: (context, index) {
return const MyListItemWidget(item: items[index]);
}
// Dividir widgets complejositemBuilder: (context, index) {
return ComplexItemWidget(item: items[index]);
}