ListView.Builder in Flutter

Create efficient, dynamic, high-performance lists

Download Complete Examples

What 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

Task List
1
Comprar víveres
Supermercado
2
Reunión de trabajo
10:00 AM
3
Gimnasio
6:00 PM
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

Productos Destacados
📱
iPhone 14
\$999
💻
MacBook Pro
\$1999
Apple Watch
\$399
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

20 items
60px
8px

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]); }

Additional Resources

📚 Official Documentation

See the complete ListView.Builder documentation

View Documentation

🎥 Video Tutorial

Learn with practical examples of ListView.Builder

View Tutorial

💡 Advanced Examples

Discover complex implementations and optimizations

Explore Examples