This tutorial explains what is Builder
widget in Flutter and when to use it.
If you ever heard about Builder
widget in Flutter but do not really understand what it is used for, you can read this tutorial. I am going to gives some examples of what kinds of situations are suitable to use the Builder
widget.
Using Builder
Widget
Builder
is described as a stateless utility widget that uses its builder
callback in its build
method to create a child widget. Below is the constructor.
const Builder({
Key? key,
required WidgetBuilder builder,
})
The question is why we need to use it, instead of directly creating the child widget. To make you understand it, let's say we want to create a button that checks whether the Flutter application has an AppBar
.
Checking whether the AppBar
exists can be done from the hasAppBar
property of the ScaffoldState
. So, you have to get the ScaffoldState
object first. You can obtain the ScaffoldState
by calling Scaffold.of
method. The method finds the closest ScaffoldState
ancestor in the tree based on the passed BuildContext
. Therefore, the passed BuildContext
must be the correct one.
Below is an example that doesn't work.
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
body: Center(
child: FilledButton(
onPressed: () {
print(Scaffold.of(context).hasAppBar);
},
child: const Text('Woolha.com'),
),
),
);
}
}
When calling Scaffold.of
, the passed context
object is the BuildContext
of the Home
widget which is above the Scaffold
widget in the tree. In addition, if you use that context
object, the Scaffold
widget has not been created yet. As a result, you'll get the following error when the button is clicked.
======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Scaffold.of() called with a context that does not contain a Scaffold.
No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This usually happens when the context provided is from the same StatefulWidget as that whose build function actually creates the Scaffold widget being sought.
A possible solution is by creating a widget class for the button. A Flutter widget has a build
method which has one parameter of type BuildContext
. When the build
method is invoked, the passed context object is the current widget's. Since MyButton
is under the Scaffold
widget in the tree, the code below should work as expected.
class MyButton extends StatelessWidget {
const MyButton({super.key});
@override
Widget build(BuildContext context) {
return FilledButton(
onPressed: () {
print(context.widget);
print(Scaffold.of(context).hasAppBar);
},
child: const Text('Woolha.com'),
);
}
}
Then, modify the Home
widget to use the MyButton
widget.
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
body: const Center(
child: MyButton(),
),
);
}
}
However, for a simple widget, you may not prefer to create another class to be able to get the right BuildContext
. In this scenario, you can use the Builder
widget to build the button.
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
body: Center(
child: Builder(builder: (BuildContext context) {
return FilledButton(
onPressed: () {
print(Scaffold.of(context).hasAppBar);
},
child: const Text('Woolha.com'),
);
}),
),
}
}
The Builder
widget makes it possible to access the BuildContext
of the current widget. In the example above, the Builder
passes its BuildContext
to the button widget. Since the Builder
is below the Scaffold
widget in the tree, it becomes possible to get the ScaffoldState
.
Full Code
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 const MaterialApp(
title: 'Woolha.com Flutter Tutorial',
home: Home(),
);
}
}
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
// body: Center(
// child: FilledButton(
// onPressed: () {
// print(Scaffold.of(context).hasAppBar);
// },
// child: const Text('Woolha.com'),
// ),
// ),
// body: const Center(
// child: MyButton(),
// ),
body: Center(
child: Builder(builder: (BuildContext context) {
return FilledButton(
onPressed: () {
print(Scaffold.of(context).hasAppBar);
},
child: const Text('Woolha.com'),
);
}),
),
);
}
}
class MyButton extends StatelessWidget {
const MyButton({super.key});
@override
Widget build(BuildContext context) {
return FilledButton(
onPressed: () {
print(Scaffold.of(context).hasAppBar);
},
child: const Text('Woolha.com'),
);
}
}
Summary
In this tutorial, we have learned how to use the Builder
widget in Flutter. It can be useful when the tree contains an inherited widget that can be accessed by using a method like Scaffold.of
, which requires a correct BuildContext
. By using it, you don't need to create a new widget class.
You can also read about:
- How to use
LayoutBuilder
widget in Flutter, if you need to build a widget based on the constraints from the parent.