Lists

ListView(children:) for a handful, ListView.builder(itemCount, itemBuilder) for thousands: itemBuilder is Unit 1's getView reborn, building only the rows that scroll into view, with ListTile as the ready-made row.

11 min read · 10 cards · 2 checks

Read in: English · हिन्दी · ગુજરાતી


Theory

The event list, third and final time

This subject OPENED with the fest's event list: Android's ListView, an adapter, getView, recycled thalis. Twenty-two lessons later the same 40 events need listing in Flutter.

This is deliberate: watching ONE problem solved by 2 frameworks is where real understanding lives. Flutter's answer has 2 forms: an eager one for handfuls: and a lazy one whose heart, when you meet it, will make you smile in recognition.

Theory

Form 1: the eager ListView

ListView(children: [widgetA, widgetB, widgetC])

Hand it the children; it scrolls them. Every child is built immediately, whether visible or not: perfectly fine for a SETTINGS page of 8 rows, wasteful for anything that grows.

Because a ListView scrolls itself, Unit 1's law crosses over intact: never wrap one in another same-axis scroller: gesture wars know no framework.

Practical

Form 2: the lazy builder (read itemBuilder twice)

final events = List.generate(40, (i) => 'Event ${i + 1}');

ListView.builder(
  itemCount: events.length,             // how many rows exist
  itemBuilder: (context, index) {       // called ONLY for visible rows
    return ListTile(
      leading: const Icon(Icons.event),        // the left slot
      title: Text(events[index]),              // main line
      subtitle: const Text('Main Ground'),     // secondary line
      trailing: const Icon(Icons.chevron_right),
      onTap: () {
        // open this event's booking screen
        debugPrint('Tapped ${events[index]}');
      },
    );
  },
)

Theory

itemBuilder is getView, reborn

Line the 2 frameworks up:

  • Android's adapter answered getView(position, ...): build/refill the row for this position
  • Flutter's itemBuilder(context, index): build the row for this index

Same contract: a function that manufactures ONE row on demand. And the recycling? Flutter's builder is lazy by design: rows are built only as they scroll into view and disposed as they leave: the convertView dance you hand-coded in Unit 1, now performed by the framework with no null-check for you to forget. 40 events or 40000: only the visible dozen exist at any moment.

Theory

ListTile: the row you stop hand-building

Unit 1's custom row needed a layout XML and findViewById choreography. Flutter ships the standard row as a widget, ListTile, with named slots:

  • leading: the left slot: icon or avatar
  • title / subtitle: main and secondary lines
  • trailing: the right slot: a chevron, a price
  • onTap: the built-in row tap

Richer rows than ListTile allows? Return any widget tree from itemBuilder: a Card holding your own Column: composition, as ever. And dividers between rows: ListView.separated, which adds a separatorBuilder alongside.

Quiz

For a 5000-row list, why is ListView.builder dramatically better than ListView(children: [...])?

  1. builder rows are cached to disk automatically
  2. itemBuilder is called lazily, only for rows scrolling into view: a dozen live rows instead of 5000 built up front
  3. builder lists scroll faster because they skip animations
  4. There is no real difference: both build all rows
Show the answer

itemBuilder is called lazily, only for rows scrolling into view: a dozen live rows instead of 5000 built up front

The children form constructs all 5000 widgets before the first frame: memory and jank: while builder manufactures rows on demand and disposes them off-screen: only the visible handful exist. This is Unit 1's recycling insight (few thalis, endless queue) made automatic: Android asked you to honour convertView; Flutter's builder simply never builds what is not needed. Options A and C invent mechanisms: no disk cache, no animation skipping: laziness alone is the win. The exam phrasing to keep: builder = lazy, on-demand construction of visible items.

Think first

Translate your Unit 1 vocabulary

Complete the dictionary from Android's ListView to Flutter's, entry by entry: adapter, getView(position), convertView recycling, setOnItemClickListener, notifyDataSetChanged. Then tap.

Show the answer

Adapter: the builder constructor itself (data + row factory in one place). getView(position): itemBuilder(context, index). convertView recycling: automatic laziness: no null-check, the framework builds/disposes. setOnItemClickListener(position): onTap on the row you build: the index is already in scope, no listener juggling. notifyDataSetChanged: setState around the data change: the one Flutter answer to every update. Five entries, one lesson: frameworks change the spelling; the LIST stays the same problem.

Watch out

List slips

children form for big data: compiles, runs, janks: reach for builder the moment the list is data-driven.

Forgetting itemCount: an infinite builder happily asks for index 40 of a 40-item list: RangeError: itemCount is the fence.

A ListView inside a Column without bounds: unbounded-height errors: give it an Expanded wrapper (the stripes lesson's cousin).

Mutating the list without setState: rows will not appear or vanish: the controlled law governs data too.

Theory

The circle closes

First lesson of this subject: an Android list, an adapter, recycled rows. Third-last lesson: the same list, and the adapter idea so absorbed that Flutter's version reads as an old friend. That arc IS the subject: patterns over platforms. Two lessons remain: dialogs and tooltips (the polite interruptions), then toast, switch, charts and the Form that finishes FestConnect Flutter for good.

Summary

Key takeaways

  • ListView(children:) builds every row up front: for small fixed lists only.
  • ListView.builder(itemCount, itemBuilder): lazy: rows built only as they scroll into view, disposed after.
  • itemBuilder(context, index) is Unit 1's getView(position) with recycling made automatic.
  • ListTile: leading / title / subtitle / trailing / onTap: the ready-made Material row; richer rows are any widget tree.
  • ListView.separated adds dividers via separatorBuilder.
  • Lists scroll themselves (no nesting in same-axis scrollers); data changes go through setState.
  • Memory hook: builder builds only what the eye can see.

Study this properly

This page is the lesson to read. In Gri-Learn the same topic is a graded deck: the self-checks are scored and your weak topics are tracked. Free to start.

Start this topic

Already have an account? Sign in

More from Flutter widget (Constructor, attributes and Properties)

Gri-Learn · syllabus-mapped B.C.A. lessons in English, Hindi and Gujarati

Lists · Mobile Application Development - 2 (option B) · Gri-Learn