Flutter Widgets explained - LLF #4
Tags: flutter, dart, tutorial, beginners
Published: 2021-09-05 10:40:44

Hey there 👋

So far in this series, we've covered what Flutter is, how to set up the development environment, and dissected the starter project file by file. So the next logical step would be to get a better understanding of Widgets, as they are the foundation of Flutter's UI. 

In this post, we will cover what Widgets are, the different types available, and finally how to use and create them.

----

> There is a repo that complements this post [here](https://github.com/nombrekeff/lets-learn-flutter/tree/master/apps/llf_4_what_are_widgets).

----

## What are Widgets?
Flutter emphasizes widgets as a **unit of composition**. This means that they are the **building blocks** of a Flutter app interface. From a text or image, to how they are laid out on the page, almost everything is composed of widgets.

They form a hierarchy based on composition, also known as the widget tree. Each widget nests inside its parent and each widget receives "context" from its parent (_the context is just some information about the location of the widget in the tree_). This tree structure goes all the way up to the root widget. You could also imagine the widget tree as similar to the DOM but not the exactly the same (_[read more]([this](https://flutter.dev/docs/resources/architectural-overview#widgets))_).

**This is how a tree of widgets looks like:**
```dart
ListView(
  children: const [
    Text('ListView is my parent'),
    ListTile(
      title: Text('My parent is ListTile'),
      trailing: Icon(Icons.check),
    )
  ],
);
```
[Complete example](https://github.com/nombrekeff/lets-learn-flutter/blob/master/apps/llf_4_what_are_widgets/lib/screens/initial_example_screen.dart)

----

### Categories of widgets
From the research I've done, these are the main categories people seem to combine widgets in:
* Accessibility
* Animation and Motion
* Assets, Images, and Icons
* Async
* Basics
* Input
* Interactive 
* Layout/structural
* Painting and effects
* Scrolling
* Styling
* Text

Flutter provides a set of pre-made Widgets, that help you build apps that follow [Material Design](https://flutter.dev/docs/development/ui/widgets/material) or [Cupertino style](https://flutter.dev/docs/development/ui/widgets/cupertino).

Let's break down some of them:
#### Layout/structural 

They have no visual representation, they just control some aspect of the layout of one or more widgets. For example a Column, Row, Padding, etc... 

**Example of a structural Widget:**
```dart
Column(
  children: [
    Text('Element 1'),
    Text('Element 2'),
  ]
);
```
[Complete example](https://github.com/nombrekeff/lets-learn-flutter/blob/master/apps/llf_4_what_are_widgets/lib/screens/structural_widget_screen.dart)

The `Column` widget, will position the child widgets in a column or vertical direction.
![Screenshot showing the app resulting from the previous code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qaiszgfjeymce04y8cl.jpeg)


#### Interactive 

These are widgets that provide interactivity, for example, a button, a text field, a scrollable list, etc...

**Example of an Interactive Widget:**
```dart
ElevatedButton(
  onPressed: () {
    print('Click!');
  },
  child: const Text('A button'),
),
```
[Complete example](https://github.com/nombrekeff/lets-learn-flutter/blob/master/apps/llf_4_what_are_widgets/lib/screens/interactive_widget_screen.dart)

The `ElevatedButton` widget, will render a button that responds to events, like `onPressed`. This event will execute whenever the user presses/clicks the button.
![Screenshot showing the app resulting from the previous code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lt5ac3xg8jfquswtm1pd.jpg)


#### Accessibility 
These are widgets that help with making our apps more accessible.  

----

### Types of widgets
When writing flutter apps, we will use two kinds of widgets, depending on whether the widget has a state or not:

#### Stateless Widget
These are widgets that have no mutable state, meaning they will not change over time (for example a label or an icon)
```dart
const Text('I am a stateless widget!');
```

The `Text` widget is stateless, as it does not need to keep any state, no value will change internally.

[read more][StatelessWidget]

#### Stateful Widget
These types of Widgets do have a mutable state, meaning they will react whenever the state changes, like a counter widget or in the following example a text field (or text input):

```dart
TextField(
  obscureText: true,
  decoration: InputDecoration(
    border: OutlineInputBorder(),
    labelText: 'Password',
  ),
);
```
The `TextField` widget is stateful because it has to keep track of the value of the field and react whenever the user types on the keyboard.

[read more][StatefulWidget]


### How do widgets update?
Flutter apps update their UI in response to events, such as a user interaction like a tap/click, or a state change.

These events tell Flutter that they need to replace a widget in the hierarchy with another widget. Flutter compares both the old and new widgets and efficiently updates the UI. Similar to VDOM if you're familiar with that, though not exactly the same ([more info here](https://flutter.dev/docs/resources/architectural-overview#rendering-and-layout)).

----

## Using widgets
Using widgets is rather easy, we just instantiate them wherever we like, like any other class. Note that using the **new** keyword is optional in Dart, which makes for cleaner code as loads of classes are instantiated all over the code.

For example, if we want to create a piece of text centered on the page, we could compose it like this:
```dart
build(context){
  return Center(
    child: Text('I see 4 widgets up my tree!'),
  );
}
```

Or like this:
```dart
build(context){
  return Column(
    mainAxisAligment: MainAxisAligment.center,
    srossAxisAligment: CrossAxisAligment.center,
    children: [Text('I see 4 widgets up my tree!')],
  );
}
```

Most widgets accept either `child` or `children` arguments, and each widget will manipulate or position those children in some way. Some will put them side by side, whilst others will make your widget contortionate in such ways that defy physics...

Let's see a complete example:
```dart
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Home Page'),
        ),
        body: Center(
          child: Column(
            children: [
              const Text('Hello World'),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  print('Click!');
                },
                child: const Text('A button'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
```
[Complete example](https://github.com/nombrekeff/lets-learn-flutter/blob/master/apps/llf_4_what_are_widgets/lib/screens/complete_example_screen.dart)

We can see that `MyApp` is a widget that returns more widgets nested hierarchically. Flutter apps are composed by combining [premade widgets](https://flutter.dev/docs/development/ui/widgets) like `Scaffold` or `AppBar`, and custom widgets created by ourselves (_like the one created further down_) or by third-party developers.

The above example will result in a widget tree like this:
![Image of example's widget tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5nb5l0nk1idow6kyjt2.png)

And would render like this, when run on a mobile device (Android in this example): 
![Screenshot showing the app resulting from the previous code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mmj4wwgq6c8yi08mpls8.jpg)

----

## Creating Widgets
Widgets are usually composed of many smaller, single-purpose widgets that combine to create more powerful ones. Flutter emphasized the importance of keeping the class hierarchy shallow, meaning that whenever possible, the **widgets should be small, composable, and do one thing well**.

As we've seen at the start of the post, Flutter apps are built by composing widgets. But we are not restricted to the widgets Flutter offers. We can create custom widgets too, let's see a basic example of how to do that.

To create a widget we need to create a class that extends from either [`StatelessWidget`][StatelessWidget] or [`StatefulWidget`][StatefulWidget], and override the build method. What the build method returns will determine the visual representation of your widget.

For the custom widget, let's create a to-do list item widget. It will have text on the left, and an icon on the right. 
```dart
class TodoListItem extends StatelessWidget {
  final bool isComplete;
  final String label;

  const TodoListItem({
    Key? key,
    this.isComplete = false,
    this.label = 'TODO',
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 16),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label),
          Icon(isComplete ? Icons.check : Icons.close),
        ],
      ),
    );
  }
}
```
[See complete widget](https://github.com/nombrekeff/lets-learn-flutter/blob/master/apps/llf_4_what_are_widgets/lib/widgets/todo_list_item.dart)


After that, we can use it anywhere in our app, like this:
```dart
Column(
  children: const [
    TodoListItem(label: 'Make coffee',  isComplete: true),
    TodoListItem(label: 'Drink it', isComplete: true),
    TodoListItem(label: 'Sleep', isComplete: false),
  ],
),
```
[See full example](https://github.com/nombrekeff/lets-learn-flutter/blob/master/apps/llf_4_what_are_widgets/lib/screens/custom_widgets_screen.dart)


The example above would result in something that looks like this:
![Screenshot showing the app resulting from the previous code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhq3hv4jr687d6xms5cp.jpg)

### Considerations
There are some important considerations to know when building widgets:

* `build()` method should be **free os side effects**. Meaning that the function should return a new widget tree, regardless of what was returned previously. All that heavy work is done for you by Flutter.
* The `build()` method should also be **fast and returns quickly**. Heavy computation should always be done asynchronously. 


## Summary

Widgets are the building block of Flutter's UI. There are different widgets for various kinds of use. Some of them respond to user input, like pressing a button, while others make our app more accessible or dynamic.

We can also create and compose widgets of our own in really simple and declarative ways. There is still much more to cover, more complementary posts will be heading this way to hopefully fill in all the gaps :P

### Learning more
* [Flutter architectural overview](https://flutter.dev/docs/resources/architectural-overview#widgets)
* [Introduction to widgets](https://flutter.dev/docs/development/ui/widgets-intro)
* [Material Components widgets](https://flutter.dev/docs/development/ui/widgets/material)

---- 

As always, thanks for reading. Hopefully, you now have a better understanding of what Widgets are.

And remember to comment if you have any suggestions or something you would like me to cover in these posts.

----

[< Previous Post][post-3]  ...  Next Post >

[post-3]: https://dev.to/nombrekeff/flutter-setup-llf-2-1cke
[post-5]: https://dev.to/nombrekeff/flutter-setup-llf-2-1cke
[StatelessWidget]: (https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html)
[StatefulWidget]: (https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html)