[MUSIC PLAYING]
JOHN RYAN: Have you ever wondered
what happens in those milliseconds between frames?
Those pixels don't just magically appear on screen.
So what does happen?
This is the job of Flutter's multiphase rendering pipeline.
It's Flutter's job to handle input, run animations, build
the widget tree, lay out the RenderObjects,
paint the RenderObjects, and composite everything
into a single image.
Whenever part of the widget tree receives user input, animation,
or changes in some way, Flutter enters the Build phase.
In this phase, the framework reconstructs the widget tree
by calling only the necessary Build methods.
The Build phase updates the element tree, which
updates the RenderObject tree.
RenderObjects are responsible for layout and painting.
During the Layout phase, Flutter walks
the tree of RenderObjects, passing down constraints.
Most widgets use box constraints,
which are two-dimensional constraints
for a specific type of render object called a RenderBox.
Child RenderObjects pass up a size to the parent object.
The size of the RenderBox has to be within the constraints that
were passed down.
So when you're debugging layout issues,
you can take a look at the incoming box constraints passed
to the RenderObject in question and see
what size was calculated.
Once the Layout phase is complete,
Flutter enters the Paint phase.
This is where Flutter calls the paint() method on all
the RenderObjects.
RenderObjects paint onto a canvas using methods like
drawRect() and drawLine().
If a RenderObject has children, it should paint those in its
paint() method, too.
Calling paintChild() seems like something the framework should
do.
But actually, it allows the RenderObject a lot
of flexibility.
For example, a RenderObject can draw more
on top of its children.
After the painting is done, it's time for the compositing phase.
Compositing means combining images into a single picture.
But what do we need to combine?
Well, painting doesn't happen on a single canvas.
To see why, think about scrolling a block of text.
When the user scrolls down, we shouldn't
need to update the text again, only the scroll bar.
We just need to reposition the text.
To solve this, Flutter uses another tree, the layer tree.
This tree contains all the paint operations for each layer.
Lower layers are painted last, and everything
is sent to the Flutter Engine to be rasterized.
By the way, each layer is painted separately,
so Flutter tries to group multiple RenderObjects
into the same layer.
But if you wrap a widget in a RepaintBoundary(),
Flutter will give its RenderObject its own layer.
And this can be a way to avoid extra painting.
Finally, the engine receives the updated layer tree
containing the drawing instructions
and converts them into pixels.
This is a process called rasterization.
If parts of the layer tree remain unchanged,
the engine can reuse those pixels.
So don't forget to try a RepaintBoundary()
if you're seeing a lot of unnecessary painting.
Creating a separate layer can be a useful tactic
for performance.
For more on Flutter's render pipeline,
check out the links below and head on over to flutter.dev.
[MUSIC PLAYING]