Based on the InheritedWidget, a simple data-driven model is implemented, and the model structure is as follows:
1. Data storage
Create an InheritedProvider using the InheritedWidget
import 'package:flutter/material.dart';
class InheritedProvider<T> extends InheritedWidget {
final T data;
InheritedProvider({@required this.data, Widget child}) : super(child: child);
@override
bool updateShouldNotify(InheritedProvider<T> oldWidget) {
// Simply return true here, and each update calls didChangeDependencies on its descendants
return true; }}Copy the code
2. Notification of change
The ChangeNotifier component of Flutter encapsulates the tool class ChangeNotifierProvider to respond to data changes and trigger UI updates.
class ChangeNotifierProvider<T extends ChangeNotifier> extends StatefulWidget {
final Widget child;
final T data; // Shared data model that requires inheritance from ChangeNotifier
const ChangeNotifierProvider({
Key key,
this.child,
this.data,
}) : super(key: key);
///Provides methods for subtrees to get shared data
static T of<T>(BuildContext context) {
final provider =
context.dependOnInheritedWidgetOfExactType<InheritedProvider<T>>();
return provider.data;
}
@override
_ChangeNotifierProviderState createState() =>
_ChangeNotifierProviderState<T>();
}
class _ChangeNotifierProviderState<T extends ChangeNotifier>
extends State<ChangeNotifierProvider<T>> {
///Rebuild the InheritedProvider if the data changes (the Model class calls notifyListeners)
void update() {
setState(() => {});
}
@override
void didUpdateWidget(ChangeNotifierProvider<T> oldWidget) {
///When the Provider updates, if the old and new data are not "==", unbind the old data listener and add the new data listener
if(widget.data ! = oldWidget.data) { oldWidget.data.removeListener(update); widget.data.addListener(update); }super.didUpdateWidget(oldWidget);
}
@override
void initState() {
widget.data.addListener(update);
super.initState();
}
@override
void dispose() {
widget.data.removeListener(update);
super.dispose();
}
@override
Widget build(BuildContext context) {
returnInheritedProvider<T>( data: widget.data, child: widget.child, ); }}Copy the code
Principle: use InheritedWidget as the parent node, when the data update, data model after ChangeNotifier associated, trigger _ChangeNotifierProviderState setState method, refresh the UI.
Encapsulation NotifyConsumer
Explicitly call directly ChangeNotifierProvider. Of access to Shared data semantic opacity, we will do a simple layer of packaging used for their children to get the data:
///Consumers who respond to changes in data
class NotifyConsumer<T> extends StatelessWidget {
final Widget Function(BuildContext context, T value) builder;
const NotifyConsumer({Key key, @required this.builder}) : super(key: key);
@override
Widget build(BuildContext context) {
returnbuilder( context, ChangeNotifierProvider.of<T>(context), ); }}Copy the code
3. Usage:
Create a shared data model:
///Shared data model
class CountModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
// provide the increment method
void increase() {
_count++;
// Notify the listener (subscriber), rebuild the InheritedProvider, and update the status.notifyListeners(); }}Copy the code
How to use ChangeNotifierProvider:
import 'package:flutter/material.dart';
import 'package:test_interited/provider/change_notifier_provider.dart';
import 'package:test_interited/provider/notify_consumer.dart';
import 'package:test_interited/provider/test/count_model.dart';
class TestNotifierWidget extends StatefulWidget {
const TestNotifierWidget({Key key}) : super(key: key);
@override
_TestNotifierWidgetState createState() => _TestNotifierWidgetState();
}
class _TestNotifierWidgetState extends State<TestNotifierWidget> {
@override
Widget build(BuildContext context) {
return Center(
child: ChangeNotifierProvider<CountModel>(
data: CountModel(),
child: Builder(builder: (context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Builder(
builder: (context) {
// Get the shared data source
return NotifyConsumer<CountModel>(
builder: (context, value) {
return Text(value.count.toString());
});
},
),
Builder(builder: (context) {
return RaisedButton(
child: Text('on the'),
onPressed: () {
// Get the shared model and increment the dataChangeNotifierProvider.of<CountModel>(context).increase(); }); })],); }))); }}Copy the code