Affichez des listes de milliers d'éléments sans ralentissement grâce à ListView.builder, ListTile et des items extraits en widgets.
Ouvrir cette leçon dans KodokonUne application réelle affiche presque toujours des listes : messages, produits, contacts. Le constructeur ListView(children: ...) que vous connaissez construit tous ses enfants d'un coup - acceptable pour dix éléments, catastrophique pour mille. ListView.builder ne construit que les items proches de la zone visible, à la demande, au fil du défilement.
import 'package:flutter/material.dart';
class ContactsScreen extends StatelessWidget {
const ContactsScreen({super.key, required this.names});
final List<String> names;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Contacts')),
body: ListView.builder(
itemCount: names.length,
itemBuilder: (context, index) {
return ListTile(
leading: const Icon(Icons.person),
title: Text(names[index]),
);
},
),
);
}
}Deux paramètres portent tout le mécanisme : itemCount annonce le nombre total d'éléments et itemBuilder fabrique l'item d'un index donné, uniquement quand il approche de l'écran. Pour le contenu de chaque ligne, ListTile est l'allié Material : leading, title, subtitle et trailing structurent la ligne, onTap fournit l'effet d'encre au toucher. Mais dès que l'item grossit, ne le laissez pas gonfler dans itemBuilder : extrayez-le dans son propre widget.
import 'package:flutter/material.dart';
class ContactTile extends StatelessWidget {
const ContactTile({
super.key,
required this.name,
required this.onTap,
});
final String name;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return ListTile(
leading: CircleAvatar(child: Text(name[0])),
title: Text(name),
trailing: const Icon(Icons.chevron_right),
onTap: onTap,
);
}
}Un item extrait se teste isolément, se réutilise dans d'autres écrans et rend l'itemBuilder trivial. Reste un besoin fréquent : les séparateurs. ListView.separated fonctionne comme builder avec un troisième paramètre, separatorBuilder, appelé entre chaque paire d'items - le dernier élément n'est jamais suivi d'un séparateur.
import 'package:flutter/material.dart';
class ContactList extends StatelessWidget {
const ContactList({super.key, required this.names});
final List<String> names;
@override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: names.length,
separatorBuilder: (context, index) {
return const Divider(height: 1);
},
itemBuilder: (context, index) {
return ContactTile(
name: names[index],
onTap: () => debugPrint(names[index]),
);
},
);
}
}