Kodokon kodokon.com

Hochperformante Listen mit ListView.builder

Zeige Listen mit Tausenden von Einträgen ohne Ruckler an, dank ListView.builder, ListTile und in eigene Widgets ausgelagerten Einträgen.

8 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

Eine echte App zeigt fast immer Listen an: Nachrichten, Produkte, Kontakte. Der Konstruktor ListView(children: ...), den du schon kennst, baut alle seine Kinder auf einmal - in Ordnung bei zehn Einträgen, katastrophal bei tausend. ListView.builder baut nur die Einträge in der Nähe des sichtbaren Bereichs, bei Bedarf, während du scrollst.

DART
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]),
          );
        },
      ),
    );
  }
}
Nur die sichtbaren Einträge werden gebaut, selbst bei 10.000 Namen.

Zwei Parameter tragen den gesamten Mechanismus: itemCount gibt die Gesamtzahl der Einträge an, und itemBuilder erzeugt den Eintrag an einem bestimmten Index, erst wenn er sich dem Bildschirm nähert. Für den Inhalt jeder Zeile ist ListTile dein Material-Verbündeter: leading, title, subtitle und trailing strukturieren die Zeile, und onTap liefert den Ink-Ripple bei Berührung. Sobald ein Eintrag aber wächst, lass ihn nicht innerhalb von itemBuilder aufblähen: Lagere ihn in ein eigenes Widget aus.

DART
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,
    );
  }
}
Ein Listeneintrag, der zu einem wiederverwendbaren, testbaren Widget geworden ist.

Ein ausgelagerter Eintrag lässt sich isoliert testen, auf anderen Screens wiederverwenden und macht den itemBuilder trivial. Ein häufiges Bedürfnis bleibt: Trenner. ListView.separated funktioniert wie builder, mit einem dritten Parameter, separatorBuilder, der zwischen jedem Paar von Einträgen aufgerufen wird - dem letzten Element folgt nie ein Trenner.

DART
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]),
        );
      },
    );
  }
}
separatorBuilder fügt zwischen jedem Paar von Einträgen einen Divider ein.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Warum ist ListView.builder bei einer Liste mit 500 Einträgen ListView(children: ...) vorzuziehen?
    • Es sortiert die Einträge automatisch
    • Es baut nur die sichtbaren Einträge, bei Bedarf
    • Es speichert Bilder im Cache
    • Es fügt automatisch Trenner hinzu
  2. Welcher Konstruktor fügt zwischen jedem Paar von Einträgen ein Widget ein?
    • ListView.divided
    • ListView.builder
    • ListView.separated
  3. Was bringt es, einen Listeneintrag in eine eigene Widget-Klasse auszulagern?
    • Es ist nötig, damit ListView.builder überhaupt kompiliert
    • Es ermöglicht const, isoliert Rebuilds und erleichtert die Wiederverwendung
    • Es macht die Liste scrollbar
    • Es erspart dir, itemCount zu schreiben