Andy Valerio
Andy Valerio

Reputation: 861

IndexedWidgetBuilder, how does it know the index?

This is mostly a conceptual question as I'm new to Dart and I guess I'm not understanding the semantics of the language here.

In IndexedWidgetBuilder,

Widget IndexedWidgetBuilder (
BuildContext context,
int index
)

who exactly is giving a value to index?

When this "thing" is used, for example:

itemBuilder: (context, i) {
    blablabla
},

"context" and "i" are never initialized and they magically have a value. Who is defining this value and where?

Upvotes: 4

Views: 4741

Answers (1)

Richard Heap
Richard Heap

Reputation: 51751

IndexedWidgetBuilder is a typedef that defines a function that takes a BuildContext and an int, and returns a Widget.

/// Signature for a function that creates a widget for a given index, e.g., in a
/// list.
///
/// Used by [ListView.builder] and other APIs that use lazily-generated widgets.
typedef Widget IndexedWidgetBuilder(BuildContext context, int index);

So, when defining itemBuilder you are providing the Widget with a function that it can call, when it wants to build an item. When the Widget is building itself it will call this function many times to build each of its children. Simplistically, it may call this function with i=0, then 1, then 2, etc.

If your Widget only has 3 children, it would be easier to just pass then as a List, but if your Widget has a thousand children this would be inefficient - and this is where the builder comes in. The Widget will try to only call the itemBuilder function for the child widgets that it actually needs, and not for any that are, say, off the top or bottom of the screen.

So, to answer your question, the Widget passes the context and i to your itemBuilder function when it calls it (typically multiple times) to build some or all of its children. i represents the ith child, so that your builder function knows which child it is being asked to build.

Edit

The dartdoc of IndexedWidgetBuilder says that it is used by ListView.builder.

The dartdoc of ListView.builder says

Providing a non-null itemCount improves the ability of the [ListView] to estimate the maximum scroll extent. The itemBuilder callback will be called only with indices greater than or equal to zero and less than itemCount. The itemBuilder should actually create the widget instances when called.

The ListView.builder named constructor constructs a SliverChildBuilderDelegate, passing in the itemBuilder as builder.

It gets used in the SliverChildBuilderDelegate's build method, here:

  @override
  Widget build(BuildContext context, int index) {
    assert(builder != null);
    if (index < 0 || (childCount != null && index >= childCount))
      return null;
    Widget child = builder(context, index); // <- your callback is called
    if (child == null)
      return null;
    if (addRepaintBoundaries)
      child = new RepaintBoundary.wrap(child, index);
    if (addAutomaticKeepAlives)
      child = new AutomaticKeepAlive(child: child);
    return child;
  }

So, index comes from the SliverChildBuilderDelegate's build method. You could keep walking backwards to see who calls that.

Upvotes: 3

Related Questions