
Lets get into what a Widget is? A widget is a basic element of the user interface that can be anything from a button, text, image, or layout. Everything in a Flutter app is a widget, including the app itself. As we have mentioned in the previous article, Flutter is a free software tool that helps people create mobile apps for iOS, Android, and website. Google made it using a computer language called “Dart“. It lets you make apps that run quickly and look good. If you’re new to Flutter, it’s important to learn the basics of how to use it.
Flutter provides a rich set of pre-built widgets for common UI elements, such as buttons, text fields, and progress indicators, as well as more complex widgets for creating flexible layouts, such as rows, columns, grids, and stacks.
Widgets in Flutter are similar to building blocks that can be arranged and combined to create the desired layout and behavior of the app. Widgets can be either Stateful or Stateless. A stateful widget can be modified, such as when a user interacts with it, while a stateless widget does not change after being rendered on the screen.
Developers can also create their own custom widgets by combining existing widgets and adding their own custom behavior. This allows for a high degree of customization and flexibility when building Flutter apps. We’ll explore the Flutter widget system, its architecture, and the different types of widgets.
Flutter Widget Architecture
At the heart of Flutter’s widget system is the concept of a widget tree. A widget tree is a hierarchical representation of the UI, where each element is a widget. Widgets can be thought of as building blocks of the user interface, which can be composed and reused to create complex UIs. The widget tree consists of two types of nodes.
a. Stateless Widgets

These widgets are immutable, meaning that their properties cannot change once they are created. They only depend on their configuration and do not hold any internal state. Examples include Text, Icon, and IconButton.
A basic stateless widget structure in Flutter looks something like this:
class Widget extends StatelessWidget {
const Widget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
b. Stateful Widgets

These widgets can maintain mutable state over their lifetime. They store state information in a separate State object, which is created by the createState() method. Examples include CheckBox, TextField, and Slider.
A basic stateful widget structure in Flutter looks something like this:
class Widget extends StatefulWidget {
const Widget({Key? key}) : super(key: key);
@override
State<Widget> createState() => _WidgetState();
}
class _WidgetState extends State<Widget> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
Inherited Widgets
Inherited widgets are a special type of widget that can store data that is accessible by their descendants. They can efficiently propagate information down the widget tree and allow for easy access to shared resources like themes, localizations, and data.
To understand Inherited widget in more depth let’s take a look at a real world example.
import 'package:flutter/material.dart';
// Define the data you want to share
class MyData {
final int value;
MyData(this.value);
}
// Define the InheritedWidget that holds the shared data
class MyInheritedWidget extends InheritedWidget {
final MyData data;
MyInheritedWidget({required this.data, required Widget child})
: super(child: child);
// Update function
static MyInheritedWidget of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>()!;
@override
bool updateShouldNotify(MyInheritedWidget oldWidget) =>
oldWidget.data.value != data.value;
}
// Define a widget that uses the shared data
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final data = MyInheritedWidget.of(context).data;
return Text("Value is: ${data.value}");
}
}
// Define the top-level widget that sets up the shared data
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
MyData data = MyData(42);
@override
Widget build(BuildContext context) {
return MyInheritedWidget(
data: data,
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Inherited Widget Example"),
),
body: MyWidget(),
),
),
);
}
}
In this example, we first define the data we want to share using an ordinary Dart class MyData
.
Next, we define an InheritedWidget
called MyInheritedWidget
that holds an instance of MyData
. The MyInheritedWidget
has two methods: updateShouldNotify
and of
. The updateShouldNotify
method is called to determine whether to rebuild widgets that depend on the MyInheritedWidget
. In this case, we compare the new and old MyData
values to determine if a rebuild is necessary. The of
method is used to obtain an instance of MyInheritedWidget
from the widget tree.
We also define a simple widget called MyWidget
that uses the shared data. In this case, we obtain an instance of MyData
using the of
method, and use it to display a value.
Finally, we define a top-level widget called MyApp
that sets up the shared data. In this example, we create an instance of MyData
with a value of 42, and wrap the MyInheritedWidget
around the MaterialApp
widget.
When the app is run, the MyWidget
widget will automatically rebuild whenever the shared MyData
object changes.
Stateful Widget Lifecycle
Stateful widgets have a lifecycle that goes through several stages, including creating the state object, building the widget, updating the widget, and disposing of the state object.
a. createState(): Called when the framework inflates the widget, it returns a new State object.
b. initState(): Called when the state object is created, it is used for initializing data or starting animations.
c. didUpdateWidget(): Called when the parent widget changes its configuration, it is used to update the state object accordingly.
d. build(): Called whenever the framework needs to rebuild the widget, it returns a new widget tree based on the current state.
e. dispose(): Called when the state object is removed from the tree, it is used for cleaning up resources, such as animations or streams.
GlobalKey
GlobalKeys are special keys that can uniquely identify a widget across the entire widget tree. They are used to access the state of a widget from anywhere in the application or to move a widget from one part of the tree to another while preserving its state.
To understand the GlobalKey also in more depth let’s have a real world example.
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
void _showSnackBar() {
final snackBar = SnackBar(content: Text('Hello, world!'));
_scaffoldKey.currentState!.showSnackBar(snackBar);
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Center(
child: ElevatedButton(
onPressed: _showSnackBar,
child: Text('Show Snackbar'),
),
),
);
}
}
In this example, we are using a GlobalKey
to access the ScaffoldState
of a Scaffold
widget from within a child widget.
First, we declare a GlobalKey
object _scaffoldKey
of type GlobalKey<ScaffoldState>
. Then, we set the key
property of the Scaffold
widget to this key.
In the _showSnackBar
method, we use the _scaffoldKey
to access the currentState
of the Scaffold
, and then call the showSnackBar
method on it to display a SnackBar
.
This is just one example of how you can use a GlobalKey
in Flutter to access the state of a widget from a child widget. GlobalKey
can also be used for other purposes, such as accessing the position of a widget on the screen or keeping track of the focus of a particular widget.
Layout Widgets
Layout widgets help in arranging and aligning other widgets within the application. Examples of layout widgets include Container, Row, Column, Stack, and GridView.
Row
Row
is a widget that arranges its children in a horizontal line. Here’s an example:
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text('Hello'),
Text('World'),
Text('!'),
],
)
In this example, we create a Row
widget with three Text
widgets as its children. We also specify the mainAxisAlignment
property to evenly space the children along the main axis.
Column
Column
is a widget that arranges its children in a vertical line. Here’s an example:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Hello'),
Text('World'),
Text('!'),
],
)
In this example, we create a Column
widget with three Text
widgets as its children. We also specify the mainAxisAlignment
property to center the children along the main axis.
Container
Container
is a widget that provides a rectangular visual element. Here’s an example:
Container(
width: 100,
height: 100,
color: Colors.blue,
child: Center(
child: Text('Hello, world!'),
),
)
In this example, we create a Container
widget with a width and height of 100, a blue background color, and a centered Text
widget as its child.
ListView
ListView
is a widget that displays a scrolling list of widgets. Here’s an example:
ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.favorite),
title: Text('Favorite'),
),
ListTile(
leading: Icon(Icons.music_note),
title: Text('Music'),
),
ListTile(
leading: Icon(Icons.videocam),
title: Text('Videos'),
),
],
)
In this example, we create a ListView
widget with three ListTile
widgets as its children. Each ListTile
has an icon and a title.
These are just a few examples of the many layout widgets available in Flutter. You can customize these widgets and combine them in different ways to create complex layouts for your apps.
In a nutshell
At the core of Flutter’s UI development process lies its innovative widget system, which provides a straightforward and effective means for combining and reusing various UI components. This feature establishes Flutter as a versatile and powerful tool well-suited for constructing modern applications across different platforms. As developers gain a deeper understanding of the widget architecture, the lifecycle of widgets, and the diverse range of widgets available, they are better equipped to create visually appealing and high-performing user interfaces with ease. This enhanced capability ultimately contributes to an overall superior user experience and more efficient development workflows.
. . .
Website: https://www.etechviral.com
LinkedIn eTechViral: https://www.linkedin.com/company/etechviral/?viewAsMember=true
YouTube: https://www.youtube.com/channel/UCO6gMNHYhRqyzbskNh4gG_A
eTechViral Instagram: https://www.instagram.com/etechviral/