Flutter Lesson 6 of 83 2 min read
Flutter Widgets Explained: The Widget Tree
Learn what a widget is in Flutter, how widgets nest to form a tree, what BuildContext is, and how to compose your own widgets.
On this page
A widget is a description of part of the user interface. Widgets are small and are meant to be combined. A screen is built by nesting them.
Widgets nest to form a tree #
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Widget tree')),
body: const Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.flutter_dash, size: 64, color: Colors.blue),
SizedBox(height: 12),
Text('Hello!'),
],
),
),
),
),
);
}
MaterialApp
└── Scaffold
├── AppBar
│ └── Text
└── Center
└── Column
├── Icon
├── SizedBox
└── Text
child and children #
- A widget that wraps one widget takes
child:. Examples:Center,Padding,Container. - A widget that arranges several takes
children:, a list. Examples:Column,Row,Stack,ListView.
Kinds of widget #
| Kind | Examples |
|---|---|
| Shows something | Text, Icon, Image |
| Lays out other widgets | Row, Column, Stack, Padding, Center |
| Responds to input | ElevatedButton, TextField, GestureDetector |
| Structures a page | Scaffold, AppBar, Drawer |
| Does something invisible | Theme, MediaQuery, Navigator |
Even padding and centring are widgets. There are no layout properties on Text; you wrap it in a Padding or a Center.
Composition: build your own #
You make new widgets by combining existing ones in a class.
import 'package:flutter/material.dart';
class ProfileHeader extends StatelessWidget {
const ProfileHeader({super.key, required this.name, required this.role});
final String name;
final String role;
@override
Widget build(BuildContext context) {
return Row(
children: [
CircleAvatar(child: Text(name[0])),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(name, style: Theme.of(context).textTheme.titleMedium),
Text(role),
],
),
],
);
}
}
void main() {
runApp(
const MaterialApp(
home: Scaffold(
body: Padding(
padding: EdgeInsets.all(24),
child: ProfileHeader(name: 'Asha Rai', role: 'Flutter developer'),
),
),
),
);
}
ProfileHeader can now be used anywhere, like any built-in widget. Whenever a build method gets long, pull part of it out into its own widget class.
BuildContext #
Every build method receives a BuildContext. It is the widget’s location in the tree. You use it to look upwards for things provided by ancestors:
final theme = Theme.of(context); // nearest theme
final size = MediaQuery.sizeOf(context); // screen size
Navigator.of(context).pop(); // nearest navigator
Widgets are cheap and immutable #
A widget’s fields are final. To change what is on screen you do not modify a widget. Flutter calls build again and gets new widgets, then updates only what differs on screen. Creating widgets is fast, so rebuilding is normal.
Try it yourself #
Create a PriceTag widget that takes a label and a price and shows them in a Row. Use it three times inside a Column.