The book continues where we talk about data management across widgets in Flutter under the same Page.

In the first solution, we use ValueNotifier and ValueListenableBuilder to implement.

This time, I will introduce another data management method in Flutter — Notification. Notification is not, strictly speaking, a cross-widget data management solution. It only does half the job: It notifies the listener of changes in the state of the data. However, the Widget that listens to the Notification needs to handle the Notification itself. It could be setState to rebuild the UI, or, to complicate things, it could work with any other data management/refresh scheme.

Notification

Notification is a mechanism for data transfer in Flutter. On the Widget tree of a Flutter, each node can send a Notification. The Notification is passed up the current node. All parent nodes can use a NotificationListener to listen for changes to the Notification.

This mechanism for passing notifications from children to parents is called Notification Bubbling in Flutter.

Notifications are used in many places within the Flutter. For example, the Scrollable Widget distributes the ScrollNotification when the Flutter is swiped. The Scrollbar listens to the ScrollNotification to determine the position of the Scrollbar.

In addition to ScrollNotification, Flutter in the KeepAliveNotification, SizeChangedLayoutNotification, LayoutChangedNotification many subclasses.

So why is Notification able to manage data across widgets? First of all, there is a use condition for the Notification mechanism, which is the parent-child relationship. As mentioned earlier, A parent node can use a NotificationListener to listen for Notification messages from its children. Therefore, with the help of Notification, it is very convenient to transmit data change information from bottom to top.

Here is a system example to show how to retrieve scroll data from a scroll Widget using ScrollNotification.

class NotificationListenerWidget extends StatefulWidget { @override _NotificationListenerWidgetState createState() => _NotificationListenerWidgetState(); } class _NotificationListenerWidgetState extends State<NotificationListenerWidget> { final StreamController<String> _controller = StreamController(); var state = ''; @override void dispose() { _controller.close(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: <Widget>[MainTitleWidget('NotificationListener basic use '), Expanded(Child: StreamBuilder(initialData: ', stream: _controller.stream, builder: (BuildContext context, AsyncSnapshot<String> snapshot) { return Text(snapshot.data); }, ), ), Expanded( child: NotificationListener<ScrollNotification>( child: ListView.builder( itemBuilder: (BuildContext context, int position) { return ListTile( title: Text('ListTile:$position'), ); }, itemCount: 30, ), onNotification: (notification) { switch (notification.runtimeType) { case ScrollStartNotification: State = 'start rolling; break; case ScrollUpdateNotification: state =' rolling '; break; case ScrollEndNotification: State = 'stop scrolling '; break; case OverscrollNotification: State = 'scroll to edge '; break;  } _controller.add('depth:${notification.depth}\n' 'state:$state\n' 'metrics\n' '-axisDirection:${notification.metrics.axisDirection}\n' '-axis:${notification.metrics.axis}\n' '-extentAfter:${notification.metrics.extentAfter}\n' '-extentBefore:${notification.metrics.extentBefore}\n' '-extentInside:${notification.metrics.extentInside}\n' '-minScrollExtent:${notification.metrics.minScrollExtent}\n' '-maxScrollExtent:${notification.metrics.maxScrollExtent}\n' '-atEdge:${notification.metrics.atEdge}\n' '-outOfRange:${notification.metrics.outOfRange}\n' '-pixels:${notification.metrics.pixels}\n' '-viewportDimension:${notification.metrics.viewportDimension}\n'); return false; }, ), ), ], ); }}Copy the code

To get the scroll data of a scroll Widget, a NotificationListener is used at its parent node to notify the Widget of its Notification change. A NotificationListener specifies the type of Notification to receive. It can also be determined internally by runtimeType, as shown below.

Switch (notification.runtimeType){case ScrollStartNotification: print(" start to scroll "); break; Case ScrollUpdateNotification: print (" rolling "); break; Case ScrollEndNotification: print(" scrollstop "); break; Case OverscrollNotification: print(" scroll to the edge "); break; }Copy the code

Different notification types actually encapsulate different state data,

Flutter dojo-widget-excel-notificationListener

Cancelability of Notification

Since Notification is searched upward along the parent node, when it is transmitted to each parent node, the parent node can control whether the Notification can continue to be transmitted upward. The source code is shown below.

So, the onNotification callback to a NotificationListener is a function that returns a bool. When false is returned, the Notification can continue to be passed up, otherwise it will be intercepted by the parent.

The custom Notification

Flutter encapsulates many notifications. It also supports custom Notifications, which is the core principle of using Notifications for data management.

Customizing Notification is as simple as inheriting Notification as shown below.

class MyNotification extends Notification {
  MyNotification(this.msg);

  final String msg;
}
Copy the code

Next, you implement the distribution of notifications yourself.

class NotificationListenerWidget extends StatefulWidget { @override _NotificationListenerWidgetState createState() => _NotificationListenerWidgetState(); } class _NotificationListenerWidgetState extends State<NotificationListenerWidget> { String msg = ''; String msgParent = ''; bool returnValue = true; @override Widget build(BuildContext context) { return Column( children: <Widget>[MainTitleWidget(' custom Notification'), SubtitleWidget('onNotification return value controls Notification delivery '), MultiSelectionWidget('onNotification returnValue ', [true, false], [true, false], (value) {setState(() => returnValue = value);  }), NotificationListener<MyNotification>( onNotification: (notification) { setState(() => msgParent = notification.msg); return true; }, child: NotificationListener<MyNotification>( onNotification: (notification) { setState(() => msg = notification.msg); return returnValue; }, child: Column( children: [Text(' custom Msg: $Msg, parent Widget: ${msgparent-isempty? False: true}'), Builder(Builder: (BuildContext context) { return RaisedButton( onPressed: () { msg = ''; msgParent = ''; MyNotification('MyNotification').dispatch(context); }, child: Text('Send'), ); }, ), ], ), ), ), ], ); }}Copy the code

Flutter dojo-widget-excel-notificationListener

There are several things to be aware of when using custom Notification.

  • After inheriting Notification, the dispatch function can be used to distribute Notification directly.
  • A NotificationListener listens on a child node, so the context passed by the Dispatch function must be the context of the child node, so use the Builder to create the context of the child node (creating a new Widget will do the same thing).
  • The Notification to listen for must be the Child of NotificationListener, for the reasons described above.

Cultivate immortality

Since the Flutter Dojo is open source, it has been enjoyed by many Flutter learners and enthusiasts. More and more people have joined the Flutter study, so I started a Flutter community, but there were too many people. Therefore, there are three groups of “Guide to Flutter” “Flutter” refers to north “Flutter” refers to east “. Those who are interested in Flutter can leave comments.

Project Address:

Github.com/xuyisheng/f…