ValueNotifier
has a ValueListenableBuilder
widget.Stream
has a StreamBuilder
widget.Future
has a FutureBuilder
widget.ChangeNotifier
?I tried using a ValueListenableBuilder
with ChangeNotifier
but ChangeNotifier
doesn't implement ValueListenable
.
I know I could use ChangeNotifierProvider
from the Provider
package, but I'd like to know if there is a solution that doesn't require a third-party package.
ChangeNotifier is a class that provides change notification to its listeners. That means you can subscribe to a class that is extended or mixed in with ChangeNotifier and call its notifyListeners() method when there's a change in that class.
A builder is a Flutter design pattern in which the construction code of a widget is defined outside of its class. Builder functions are callback interfaces that pass data (often layout-specific) to the parent widget which returns a child based on that data.
In Flutter, the overlay lets you print visual elements on top of other widgets by inserting them into the overlay's stack. You insert a widget into the overlay using an OverlayEntry and you use Positioned and AnimatedPositioned to choose where the entry is positioned within the overlay.
We already know where to put ChangeNotifierProvider : above the widgets that need to access it. In the case of CartModel , that means somewhere above both MyCart and MyCatalog . You don't want to place ChangeNotifierProvider higher than necessary (because you don't want to pollute the scope).
What is the specialty of change notifier class in flutter? Although the main specialty is ChangeNotifierProvider listens to ChangeNotifier, it has many other advantages. In this article we will also listen to these special powers of ChangeNotifier. We consider ourselves just like other subscribers that listen to ChangeNotifier.
A stateless utility widget whose build method uses its builder callback to create the widget's child. Builder (Flutter Widget of the Week) This widget is a simple inline alternative to defining a StatelessWidget subclass. For example a widget defined and used like this:
A widget whose content stays synced with a ValueListenable. Given a ValueListenable<T> and a builder which builds widgets from concrete values of T, this class will automatically register itself as a listener of the ValueListenable and call the builder with updated values when the value changes. ValueListenableBuilder (Flutter Widget of the Week)
AnimatedBuilder, which also triggers rebuilds from a Listenable without passing back a specific value from a ValueListenable. NotificationListener, which lets you rebuild based on Notification coming from its descendant widgets rather than a ValueListenable that you have a direct reference to.
ChangeNotifier is a direct implementation of the Listenable Widget and for the Listenable, you can use AnimatedBuilder, which triggers rebuilds from a Listenable without passing back a specific value Also, your class could extend from ChangeNotifier and add new capability to it and you can create a custom Builder widget base on these new functionalities
This is a supplemental answer demonstrating using an AnimatedBuilder
to rebuild the UI on a change from a ChangeNotifier
.
It's just the standard counter app.
counter_model.dart
import 'package:flutter/foundation.dart';
class CounterModel extends ChangeNotifier {
int _counter = 0;
int get count => _counter;
void increment() {
_counter++;
notifyListeners();
}
}
main.dart
import 'counter_model.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _counterModel = CounterModel();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
AnimatedBuilder(
animation: _counterModel,
builder: (context, child) {
return Text(
'${_counterModel.count}',
style: Theme.of(context).textTheme.headline4,
);
}
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _counterModel.increment,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
You can wirte a simple widget by yourself.
use setState
as a listener for a ChangeNotifier
.
class ChangeNotifierBuilder<T extends ChangeNotifier> extends StatefulWidget {
const ChangeNotifierBuilder({
Key? key,
required this.value,
required this.builder,
}) : super(key: key);
final T value;
final Widget Function(BuildContext context, T value) builder;
@override
_ChangeNotifierBuilderState<T> createState() =>
_ChangeNotifierBuilderState<T>();
}
class _ChangeNotifierBuilderState<T extends ChangeNotifier>
extends State<ChangeNotifierBuilder<T>> {
@override
void initState() {
widget.value.addListener(_listener);
super.initState();
}
@override
void didUpdateWidget(covariant ChangeNotifierBuilder<T> oldWidget) {
if (widget.value != oldWidget.value) {
_miggrate(widget.value, oldWidget.value, _listener);
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
widget.value.removeListener(_listener);
super.dispose();
}
void _miggrate(Listenable a, Listenable b, void Function() listener) {
a.removeListener(listener);
b.addListener(listener);
}
void _listener() {
setState(() {});
}
@override
Widget build(BuildContext context) {
return widget.builder(context, widget.value);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With