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.
What is Flutter?
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.
Dart: The programming language
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.
// Defining a function
foo({@required String param1, String param2}) {}
// Calling the function
foo(param1: 'Hello', param2: 'World');
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.
class Foo() {
String _param;
Foo(this.param);
Foo.bar(otherParam) {
// Do stuff
}
}
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 new
keyword:
Foo foo = Foo();
Getting Started
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.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return Container();
}
}
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 StatelessWidget
or 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
. The 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 child
.
For instance, the following code snippet would create a container, and center the text within it.
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text("Hello World"),
),
);
}
}
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 AppBar
.
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: Center(
child: Text("Hello World"),
),
),
),
);
}
}
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 style
-parameter.
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("My very first Flutter App"),
),
body: Container(
child: Center(
child: Text(
"Hello World",
style: TextStyle(color: Colors.red, fontSize: 24),
),
),
),
),
);
}
}
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.
What now?
To learn more about StatefulWidgets, Navigation, List/detail and some simple animation, check out the second part this article series, 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.
Top comments (0)