Flutter is getting a lot of attention these days, and rightly so. It is one of the fastest growing frameworks, and it just surpassed React Native in GitHub stars - if that counts for anything. In this two-part article series, we will first introduce what Flutter is, and how to use it. Then in the second part we will apply our newfound knowledge and build a simple Pokedex app.
Flutter is Googles take on a cross-platform framework, but it is taking the ‘cross-platform’-term to the next level. Every cross-platform framework should at least be able to support both iOS and Android with one single codebase. However, Flutter offers more than that. You can export your Flutter codebase to both iOS and Android, but also web (in beta), and macOS (in alpha). The Google team is also working on Windows and Linux support - both are in technical preview as of January 2020. Thus, with Flutter you will be able to cover almost any platform with one single codebase – which is quite amazing.
The programming language chosen by Google is Dart. This implies that everything in Flutter is built using Dart. This should not scare you though, because Dart got many similarities with other object-oriented languages, so if you know a bit of TypeScript or C# you will quickly comprehend Dart. There are a few Dart-specific features, I would like to introduce, before we develop our first app.
Firstly, Dart supports what is called named parameters, which is heavily used in Flutter. This simply means you can name each parameter in your function or constructor. This is utilized by wrapping your variable with curly braces. The curly braces also make the variable optional, but if the variable is required then it is possible to annotate it with @required – you can of course also omit the curly braces, then the function is used as expected.
Dart also supports named constructors. This feature gives the possibility to have multiple constructors in a class, each constructor will construct an object in a specific way.
There are some smaller features worth highlighting. In the code snippet for the Foo-class, the parameter named
_param is prefixed with an underscore. The underscore makes that variable private. Furthermore, the parameter in the
Foo-constructor is prefixed with
this, which assigns it to the variable in the class. Using Flutter, you will constantly be instantiating new objects, but in Dart you can omit the
For installing Flutter a guide can be found on flutter.dev.
After installation you should be able to run the command
flutter create myapp, that will create an app called
myapp. Navigate to the
lib/main.dart file and delete everything – we will build from scratch. In Flutter you start the application by calling
runApp() in the
main-function parsing the widget, which will be the root widget of your app.
In this little code-snippet there are already a couple of Flutter concepts at play. Everything in Flutter is a widget. This means, that every time you want to draw something on the screen, you will either inherit from
StatefulWidget. In both cases you will need to overwrite the
build-method, but we will get back to that method shortly.
As used in the previous code-snippet, a
StatelessWidget is a widget, that does not contain any mutable state, and only depends upon the parent configuration. The
StatelessWidget is mainly drawn in two situations: when the widgets are constructed and inserted in the widget tree, or when the parent changes its configuration.
So when should I inherit from
StatefulWidget? If you need some internal mutable state in the widget, you will inherit from
StatefulWidget, which gives you a separate
State-class and a
setState()-method, that will redraw the widget. An example of a
StatefulWidget is a CheckBox. The internal state of the CheckBox is whether or not it is checked.
A big part of learning Flutter is to learn what built-in widgets Flutter has to offer. As I said earlier: everything in Flutter is a widget, so building an app in Flutter is mainly assembling different widgets. This happens in the build-method. The
BuildContext is a little out of scope for this article, so just ignore it for now. The
build-method returns the widgets that should be rendered. In this case it is just an empty
Container-widget is like a HTML div element, and takes a named parameter called
child, that takes a new widget, and that is how the tree is built. A lot of the built-in widgets have this named parameter
For instance, the following code snippet would create a container, and center the text within it.
However, the code-snippet does not work, because the root of our app should look a little different. A very typical Flutter setup is with a
MaterialApp-widget, that has a
Scaffold as home. The
MaterialApp-widget gives the possibility to set settings for the entire app, such as language or theme colors. The
Scaffold is a skeleton for the app.
Scaffold makes it easy to create things such as an
If we expand a little upon it, we can see how the
Scaffold can be used to create the
Appbar – which of course is just a widget. The
AppBar-widget has, among others, a named parameter called
title, which takes another widget. It could be any widget; in this example it is a
Text-widget. We are also adding some simple styling to the ‘Hello World’ text by adding a
TextStyle to the
That gives the following result:
The whole tree-analogy, which is used throughout this article, becomes clearer now. The widget tree in this simple app looks like the following, where
MaterialApp is root.
To learn more about StatefulWidgets, Navigation, List/detail and some simple animation, check out the second part this article series (stay tuned), where we will expand upon our Flutter-knowledge and build a Pokedex.
If you think Flutter looks cool, I strongly recommend looking at the official Widget Catalog, that gives an overview of the most used Widgets. Besides that, there is also the Flutter Codelabs, and Flutter YouTube channel which you should check out.