[MUSIC PLAYING]
CRAIG LABENZ: One of the first things new Flutter developers
learn about is the ListView widget, because it's
so easy to use when you need your widgets to scroll.
And once you know about this, all is well in scrolling land,
until one of the widgets you want
to parade through your viewport is itself a ListView.
Suddenly, Flutter is barking at you about viewports,
receiving unbounded dimensions, and well, many things
are unwell in scrolling land.
What the Flutter?
If you've seen this error in the past and read Flutters message,
you probably saw the suggestion to set Shrink Wrap to true.
You did that and the error went away
and peace was restored to scrolling land.
The only problem was a threat was still lurking.
Shrink Wrap can be a costly performance hit.
To understand why, let's refresh our understanding of lists.
Imagine you're below deck on a cruise ship looking out
a porthole.
Suddenly, a large school of fish starts swimming by.
You're not moving anywhere, but the fish
are zipping through your field of vision.
You have no idea how many fish are to come.
For all you know, it could be an infinite line
of fish stretching deep into outer space.
Either way, you can only see a few fish at any one time.
And this is how ListViews work.
The porthole in our analogy is the space
that you allot for your ListView,
and the fish swimming by are your widgets.
And this idea of a specific viewport
is critical when you consider what Flutter
has to deal with when one of the widgets it encounters
is itself a ListView.
Now suddenly there's two portholes?
How is this supposed to work?
Well, the fact is it can't.
And so Flutter requires your inner list
to completely evaluate itself and figure out its full size
up front and then proceed by your top level viewport,
behaving as if they're all just one widget.
You might have guessed it, but that's
exactly what Shrink Wrap does.
It forcibly evaluates an entire list of widgets.
And now you might be guessing another thing,
how this could be a big performance problem?
If one of those inner lists contain lots of widgets,
especially if they have animations,
when it approaches your viewport and Flutter
is forced to render it completely,
you're at a high risk for dropped frames, jank, stutters,
the worst.
The bigger your inner lists are, the more important
the following change is.
Let's look at some code.
Imagine you have this scenario, a ListView comprised entirely
of ListViews.
If you set Shrink Wrap to true on each inner list
and set never scrollable scroll physics,
Flutter will technically be able to render your UI.
But remember that danger still lurks.
Luckily, the fix we need to implement is very simple.
First, replace the outer ListView.builder
with a custom scroll view.
Second, change our inner list of widgets from ListViews
to SliverLists.
Third, we grab all the widgets we
were putting in those inner list views
and put them in Sliver Lists instead,
which require a delegate.
Now, I don't know about you, but delegates always
make me think something scary is about to happen.
But luckily, this one isn't scary.
If you're converting from inner ListView.builders,
a great choice is the SliverChildBuilderDelegate,
because it looks so similar.
Copy over that indexed widget builder
function from your old ListViews, this time using it
as a positional parameter.
And you're done.
You can now scroll through your list of lists,
knowing that each inner list is still building efficiently,
only rendering whatever fish are currently
in front of your viewport.
To play with this yourself, check out the DartPad link
below.
Notice how the behavior of the build methods
print statement changes from step one with Shrink Wrap
and step two with Slivers.
That's a huge performance improvement.
For more info on Flutter, head to Flutter.dev.
[MUSIC PLAYING]