This tutorial shows you how to use the ValueListenableBuilder
widget in Flutter.
In an application, sometimes you may need to display a component whose content must always be updated when a value changes. Creating such a component or widget in Flutter can be done easily by using the ValueListenableBuilder
widget. It's a widget whose content stays synced with a ValueListenable
. Below are the usage examples.
Using ValueListenableBuilder
The constructor of ValueListenableBuilder
can be seen below.
ValueListenableBuilder({
Key? key,
required ValueListenable valueListenable,
required Widget Function(BuildContext, T, Widget?) builder,
Widget? child,
})
The constructor has two required arguments. The first one is valueListenable
, which is used to pass a ValueListenable
to which the widget depends on. ValueListenable
is an interface for subclasses of Listenable
that expose a getter named value
. The second one is builder
, which is used to build a widget based on the current value.
The ValueListenable
is an abstract class. That means you need to use a non-abstract class to create the instance. Flutter provides a class called ValueNotifier
, which is an extension of ChangeNotifier
that implements ValueListenable
. It's suitable for cases where there is a single value.
For the builder
argument, you have to pass a function that returns a Widget
. The function has three parameters. The first parameter is the BuildContext
of the ValueListenableBuilder
widget. The second parameter is the current value whose type depends on the value type of the ValueListenable
instance. The last parameter is the Widget
passed as the child
argument which can be useful if there's a widget subtree that doesn't depend on the value of the ValueListenable
.
class MyPageState extends State<MyPage> {
final ValueNotifier<int> _counter = ValueNotifier<int>(0);
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ValueListenableBuilder(
valueListenable: _counter,
builder: (BuildContext context, value, Widget? child) {
return Column(
children: [
Text('COUNTER'),
Text('$value'),
],
);
},
),
OutlinedButton(
onPressed: () {
_counter.value += 1;
},
child: const Text('Increment'),
),
],
),
);
}
}
In the example above, the widget subtree that displays the 'COUNTER' text doesn't depend on the value of the ValueListenable
. However, it will be rebuilt every time the value changes. In the case above, to prevent unnecessary rebuilds, you can add a const
when creating the 'COUNTER' text widget. But let's assume we have a more complex widget that doesn't have a const constructor. The unnecessary rebuilds can be prevented by passing the widget as the child
argument of the ValueListenableBuilder
. That makes the widget passed as the third argument of the builder
function.
ValueListenableBuilder(
valueListenable: _counter,
builder: (BuildContext context, value, Widget? child) {
return Column(
children: [
child!,
Text('$value'),
],
);
},
child: const Text('COUNTER'),
)
Summary
ValueListenableBuilder
is a widget that allows its content to always stay synced with a ValueListenable
. To use it, you need to pass a ValueListenable
that the widget will listen to. To return a widget to be rendered, you have to pass a builder function that will be invoked when the value changes.
You can also read about.