A Tale of Three (Flutter) Trees

Itumeleng Masuluke
Geek Culture
Published in
4 min readJan 20, 2022
Photo by Zoltan Tasi on Unsplash

Earlier this year, March 3rd to be exact, Flutter finally hit version 2. Not only did they announce that Web was finally stable and added support for foldable phones but Flutter is multi-platform now (Android, iOS, Linux, macOS, Web, and Windows). Four months later Android announced that their new “modern toolkit for building native UI”, Jetpack Compose, is now stable. React is still going strong and SwiftUI is probably something interesting in the background. With all these changes and advances in the mobile dev world, it’s pretty clear that we inevitably will or already do exist in the age of the declarative UI.

So I thought it would only be fitting to see how these frameworks/toolkits operate under the hood. So I’ll try to give a brief high-level explanation of how Flutter architecture works, at least at the rendering layer. Flutter uses three trees that work together in place of one to separate the concerns. Let’s take a look at these three trees.

The Widget Tree

If you’ve taken a look at Flutter or had conversations with Flutter enthusiasts you might have heard the phrase “Everything is a widget” pop up once or twice. What they’re usually referring to is this tree. In reality, the Widget tree isn’t the most important one. It really is only responsible for providing the widget configurations.

Widget class

If we take a look at this Widget class (with all the diagnostics code removed) we can see that the class really only does two things. The Widget class creates a new Element(which is the next tree we will look at). When traversing the Widget tree after a change it uses the canUpdate to see if it needs to replace the current widget or if it can simply update the element. One other thing to pay attention to @immutable annotation, which would mean if the widget tree was the only tree, Flutter would have to recreate the widget every single time a change is emitted which would work but nowhere as efficiently as Flutter currently works. Thank’s to the Element tree that doesn’t have to be the case

The Element Tree

The Element tree is the tree that does most of the heavy lifting. The Element is responsible for taking care of the widget’s lifecycle. This is where Flutter’s efficiency comes from, this tree is what makes sure that as much of the Widget tree is as reusable as possible. The Widgets themselves have no knowledge of any other Widgets in the tree. so the Element tree is responsible for managing parent-child relationships and moving Widgets around(reparent). The Element tree, on a very high level, has a 1 to 1 relationship with the Widget tree. So just like you get Stateless Widgets and Stateful Widgets you get Stateless Elements and Stateful Elements. The Stateless Elements won’t have to do as much work as the Stateful Elements because they don’t have to listen for changes.

The Render Tree

The render tree holds all the render objects. Render objects have all the necessary information needed to be able to paint the widget onto the screen. So unlike the Element tree, there isn’t a 1 to 1 copy of the widget tree because not all widgets have a render object for instance the Text widget and RichText widget would both just use the RenderParagraph render object. The Render tree is built from the element tree so it also benefits from only updating sections when completely necessary.

Rendering

In Flutter, parent widgets don’t have much information about their children other than instructions on how to visit them. So then how do the widgets know how to paint themselves?

Flutter walks the render tree in a depth-first traversal. The parent widget then passes down the size constraints to its children and the children respond with their sizes. Once everything has its size it is ready to paint.

As part of its engine Flutter provides a copy of Skia which is responsible for doing all the heavy lifting. Supplying its own copy of Skia removes the dependency from Android or iOS’ rendering engine which means they can ship out updates as they please.

--

--