The Four Layers

Probably you’ve already seen an overview of Flutter’s architecture in one of those ‘Intro to Flutter’ talks but somehow you weren’t ready to grasp the powerful concept behind all those different layers back then. Maybe you are like me and you just didn’t get it by simply staring at that abstract diagram for the exact 20 seconds the slide was projected onto the wall. Don’t worry, I’m here to help. Have a look at the following graphic:

The different layers of the Flutter framework. For more detail on this, head over to https://flutter.io/docs/resources/technical-overview

The Flutter framework itself is composed of many layers of abstraction: At top there are the commonly used Material and Cupertino widgets, followed by the more generic Widget layer. Most of the time you’ll find yourself using widgets from those two layers and that’s perfectly fine. The probability that you have already seen (and used) one of them out there in the vast wild should be quite high (think of the Scaffold or the FloatingActionButton from the Material library or the Column and the GestureDetector from the widgets library).

Below the widgets layer you’ll find the rendering layer which simplifies the layout and painting process and is another abstraction for the dart:ui library at the bottom. dart:ui is the last Dart layer which basically handles the communication with the Flutter engine.

To put it simply one can say that the higher levels are easier to handle whereas the lower ones give you more fine-grained control with added complexity.

1. The dart:ui library

The dart:ui library exposes the lowest-level services that Flutter frameworks use to bootstrap applications, such as classes for driving the input, graphics text, layout, and rendering subsystems.

So basically you could write a ‘Flutter’ app by just instantiating classes from the dart:ui package (e.g. Canvas , Paint and TextBox ). However, if you are familiar with directly painting onto the canvas, you know that everything that goes beyond painting a still image of a stick figure will be a pain to manage. And then think not only about painting but also about orchestrating the layout and hit-testing the elements of your app.

So what does this exactly mean? It means that you would have to manually calculate all coordinates used in your layout. Then mix in some painting and hit testing to catch user input. Do that for every single frame and keep track of that. This approach may be manageable as long as you plan on building a simple app which just displays some text centered within a blue box, but not so great if you try to build more complex layouts like a shopping app or even a small game. Don’t even dare to think of animations, scrolling or other fancy UI stuff we all love. I am telling you based on my own experience, this is endless fuel for developer nightmares.

2. The rendering library

The Flutter rendering tree. The RenderObject hierarchy is used by the Flutter Widgets library to implement its layout and painting back-end. Generally, while you may use custom RenderBox classes for specific effects in your applications, most of the time your only interaction with the RenderObject hierarchy will be in debugging layout issues.

The rendering library is the first abstraction layer on top of the dart:ui library and does all the heavy math work for you (e.g. keeping track of the calculated coordinates, etc.). In order to do that it uses so called RenderObjects . You can compare RenderObjects to the engine of a car — they are the components that do the actual work to bring your app onto the screen. This tree composed out of RenderObjects will later get layed out and painted by Flutter. To optimise this complex process Flutter uses a smart algorithm to aggressively cache those expensive computations in an intelligent way to keep the amount of work on every iteration minimal. Amazing.

Most of the time you’ll find Flutter uses a RenderBox instead of another RenderObject . That’s because the people behind the project realised that a simple box layout protocol works very well to build performant UIs. Think of every widget placed in it’s own box which is calculated and then arranged with other pre-laid-out boxes. So if only one widget of your layout changes (e.g. a button or a switch), only this relatively small box needs to be recomputed by the system.

3. The widgets library

The Flutter widgets framework. What else?

The widgets library — probably the most interesting layer — is another layer of abstraction which provides ready-to-use UI components we can simply drop into our app. All widgets you find in this library also fall in one of the following three categories which are handled by the appropriate RenderObject for you:

Layout. E.g. Column and Row widgets which make it easy for us to align other widgets vertically or horizontally to each other. Painting. E.g. Text and Image widgets allow us to display (‘paint’) some content onto the screen. Hit-Testing. E.g. the GestureDetector allows us to recognise different gestures such as tapping (for detecting the press of a button) and dragging (for swiping through a list).

Typically you will use many of those ‘basic’ widgets and compose your own widgets out of that. As an example you could build a button out of a Container which you wrap into a GestureDetector to detect a button press. This is called composition over inheritance.

However, instead of building every UI component by yourself, the Flutter team has created two libraries which contain frequently used widgets in the Material and Cupertino (iOS-like) style.

4. The Material & Cupertino library

Flutter widgets implementing Material Design & the current iOS design language.