After writing our first Flutter app in less than 30 minutes, today we’re taking a look at Flutter widgets. If you want to know what is a widget in Flutter, what are widgets types and how to use them – this article is for you πŸ™‚

What is a widget?

If you ever worked with a web framework like React, you should know the concept of components. Flutter widgets are directly inspired by this idea. Widget is a reusable piece of code, which describes how your application’s UI looks like. Widgets define the user interface by their state. In some cases, the state can be static and not change over time – see the section below about Flutter widget types for details.

As soon as a widget’s state changes, Flutter rebuilds its outlook and in effect re-renders the GUI. The framework is said to do it efficiently by measuring what has changed in the widgets tree since the last rendering and re-paints only what’s necessary.

The most basic Flutter app might look as follows:

import 'package:flutter/material.dart';
void main() => runApp(
Center(
child: Text(
"Hello Flutter!",
textDirection: TextDirection.ltr,
)),
);

The runApp() method takes a Widget as its argument. In our case, it takes a Center widget, which has one child – a Text widget. As expected, such a simple Flutter app shows a “Hello Flutter!” text at the center of the screen.

This simple example shows us a few interesting facts:

  • there are many built-in widgets, like Center and Text
  • widgets can have a child or children – this is widgets nesting and it happens all the time and can be very deep
  • Flutter widgets can have their own properties, like textDirection.

Widgets nesting sometimes makes simple Flutter apps having a lot of source code inside a single file. However, as I mentioned in the previous post, don’t get discouraged by that πŸ™‚ Actually, having a lot of nested widgets in Flutter is a good practice. If you have a few huge widgets without much nesting instead, it means that there’s something wrong with your implementation. Flutter widgets – as all reusable pieces of code – should not have too many responsibilities. SOLID also applies here πŸ˜‰

Viewing Flutter widgets with Flutter Inspector

As widgets tree may get big and quite heavily nested, there’s a very useful tool to easily view and explore it. This tool is called Flutter Inspector.

While in debug mode in Visual Studio Code, you can launch it by clicking the blue magnifier icon:

Flutter Widgets: blue magnifier button in VS Code which opens the widgets inspector
A button for opening Flutter Widgets Inspector from VS Code

It opens in a web browser and allows you to see the whole widgets tree in your app:

Flutter Widgets: Dart DevTools widgets inspector
Flutter Inspector (part of Dart DevTools)

There’s a very handy feature “Select Widget Mode” which, when enabled, lets you select the widgets directly in your emulator or phone. After doing this, you can see the selected widget’s properties in the inspector.

Types of Flutter widgets

In Flutter, you can – and will – create your own widgets. Widget is just a Dart class which extends a proper base class. Depending on whether your widget actually manages any state and changes over time, you have two types of base classes to inherit from – StatelessWidget or StatefulWidget.

The main purpose of each type of widget is to provide an implementation of a build() method which returns a Widget object. However, each widget type does it a bit differently. Let’s see this in action.

StatelessWidgets

The simplest widget you can create is a stateless widget. You create it by simply creating a class extending StatelessWidget. Here’s the sample source code and a view it generates:

import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
title: "My CodeJourney Flutter app",
home: Scaffold(
appBar: AppBar(
title: Text("My First App"),
),
body: MyFirstWidget(),
),
),
);
class MyFirstWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
child: Text(
"Hello MyFirstWidget!",
style: TextStyle(color: Colors.green),
),
);
}
}

You can play with it yourself in the DartPad.

There are quite a few new things in the source code. Let’s point them out:

  • as our main widget, we used MaterialApp and provided it to runApp() method. MaterialApp widget gives us material design for our app out of the box. As soon as you use it, you can nest more material widgets from the widgets library. There’s a similar widget for Apple-oriented widgets called CupertinoApp, which allows using Cupertino widgets
  • we used another material widget – a Scaffold. It provides us with an appBar and body properties – setting them we’re getting this nice-looking application’s skeleton with entitled app bar and home for our widget. Scaffold also gives us many things “for free”, e.g. FloatingActionButton
  • body of our Scaffold is our first own stateless widget – MyFirstWidget. As mentioned before, it overrides the build() method, which simply returns another widget tree. Notice the usage of a Container widget, which is very useful for grouping other widgets.

StatelessWidget is simple, works and is just there πŸ™‚ Let’s see something more interesting now – StatefulWidgets.

StatefulWidgets

When you want your widget to change over time and maintain its state (in most cases you do), you can create a stateful widget. You do it by creating a Dart class extending StatefulWidget. Unlike StatelessWidgets, StatefulWidget doesn’t override the build() method. Instead, it implements a createState() method, which creates the initial widget’s state (see below).

Apart from the main widget class, which itself is still “final” (or better said – immutable), you create a class extending State. This class maintains the actual state and it is now who provides the build() method’s implementation.

Let’s see the sample code and produced GUI:

class MySecondWidget extends StatefulWidget {
MySecondWidget({Key key}) : super(key: key);
@override
_MySecondWidgetState createState() =>
_MySecondWidgetState();
}
class _MySecondWidgetState extends State<MySecondWidget> {
int _clickCount = 0;
void incrementClickCount() {
setState(() {
this._clickCount++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My First App"),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: Text(
"Hello! Times clicked: "
+ this._clickCount.toString(),
style: TextStyle(
color: Colors.green,
fontSize: 20.0),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: this.incrementClickCount,
),
);
}
}

The full code you can play with is available in the DartPad.

Now some comments about the StatefulWidget code:

  • notice how MySecondWidget class passes a key to its superclass. Concept of Flutter widgets keys is interesting and we’ll dig into it in a separate post. For now, just treat it as a convention to always accept a key as a named argument and pass it to the base class
  • as said before, in this simple example, MySecondWidget only creates the initial state by instantiating _MySecondWidgetState
  • you’re already familiar with most of the code in _MySecondWidgetState, but notice the usage of setState() in incrementClickCount() function. It tells Flutter that the state has changed, so the framework can re-render the UI. If you directly change the value of this._clickCount without calling setState(), GUI will not be updated until setState() is called in some other place. We’ll talk more about state management techniques in Flutter in the future articles
  • note how easy it is to add a FloatingActionButton thanks to using Scaffold material widget.

That was easy and works nicely! You now know how to use both Flutter widget types πŸ’ͺ

Flutter quick actions in VS Code

I’d like to share with you two easy tips for working with Flutter in Visual Studio Code. Both speed up the development nicely. It assumes that you configured VS Code properly (if not read this article) and have Flutter extension installed.

Ctrl + .

First important keyboard shortcut is Ctrl+. (Cmd+. on Mac). It allows you to perform many element-contextual actions. For me it’s most useful for removing widgets or wrapping widgets with other ones:

Quick Flutter actions in VS Code (Ctrl+.)

Snippets for widgets creation

Another useful feature are code snippets for creating widgets. You use them by starting to type their acronym in your .dart file. There are two acronyms for widgets creation – stless for StatelessWidget and stful for StatefulWidget scaffolding. The usage looks as follows:

Visual Studio Code – using Flutter snippets

Most popular Flutter widgets

I wanted to list you here some most popular Flutter widgets, but they are quite well described here. You can also search through the widgets library. We’ve also used quite few of them in our examples above πŸ˜‰

Community widgets

Many more people are starting to use Flutter and they also create a lot of community widgets. You can find the Dart packages for Flutter on pub.dev. I also recommend checking the Flutter Awesome website where the best Flutter widgets, libraries and other extensions are listed.

Summary

That’s it! You’ve just learned how to use stateless and stateful widgets in Flutter. We’ve also seen what’s the difference between them and what are some basic conventions in creating them. There’s a lot more to Flutter widgets and related topics, but these are topics for separate posts. I hope to publish more of them soon πŸ™‚

In my opinion, bringing components into the mobile world in the form of widgets is a very nice idea. They give quite a good separation of logic and GUI management. For sure it’s a fresh start, totally changing the way in which we think about mobile apps development. Components have done their job in the web world, so why would widgets not succeed in mobile apps? πŸ€” We’ll see!

What do you think? If you are interested in some particular topics related to Flutter – let me know! πŸ™‚