Flutter-notification和notificatioLisener
Notification源码:
abstract class Notification { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. const Notification(); /// Applied to each ancestor of the [dispatch] target. /// /// The [Notification] class implementation of this method dispatches the /// given [Notification] to each ancestor [NotificationListener] widget. /// /// Subclasses can override this to apply additional filtering or to update /// the notification as it is bubbled (for example, increasing a `depth` field /// for each ancestor of a particular type). @protected @mustCallSuper bool visitAncestor(Element element) { if (element is StatelessElement) { final StatelessWidget widget = element.widget; if (widget is NotificationListener<Notification>) { if (widget._dispatch(this, element)) // that function checks the type dynamically return false; } } return true; } /// Start bubbling this notification at the given build context. /// /// The notification will be delivered to any [NotificationListener] widgets /// with the appropriate type parameters that are ancestors of the given /// [BuildContext]. If the [BuildContext] is null, the notification is not /// dispatched. void dispatch(BuildContext target) { // The `target` may be null if the subtree the notification is supposed to be // dispatched in is in the process of being disposed. target?.visitAncestorElements(visitAncestor); } @override String toString() { final List<String> description = <String>[]; debugFillDescription(description); return '$runtimeType(${description.join(", ")})'; } /// Add additional information to the given description for use by [toString]. /// /// This method makes it easier for subclasses to coordinate to provide a /// high-quality [toString] implementation. The [toString] implementation on /// the [Notification] base class calls [debugFillDescription] to collect /// useful information from subclasses to incorporate into its return value. /// /// If you override this, make sure to start your method with a call to /// `super.debugFillDescription(description)`. @protected @mustCallSuper void debugFillDescription(List<String> description) { } }
其中dispatch(context)是分发通知的,它会从参数context位置处开始沿着widget树向上冒泡通知。
也可以自定义Notification,比如class MyNotification extends Notification( final String msg; MyNotification(this.msg);)
NotificationListener是用来监听Notification的,源码如下:
/// A widget that listens for [Notification]s bubbling up the tree. /// /// Notifications will trigger the [onNotification] callback only if their /// [runtimeType] is a subtype of `T`. /// /// To dispatch notifications, use the [Notification.dispatch] method. class NotificationListener<T extends Notification> extends StatelessWidget { /// Creates a widget that listens for notifications. const NotificationListener({ Key key, @required this.child, this.onNotification, }) : super(key: key); /// The widget directly below this widget in the tree. /// /// This is not necessarily the widget that dispatched the notification. /// /// {@macro flutter.widgets.child} final Widget child; /// Called when a notification of the appropriate type arrives at this /// location in the tree. /// /// Return true to cancel the notification bubbling. Return false (or null) to /// allow the notification to continue to be dispatched to further ancestors. /// /// The notification's [Notification.visitAncestor] method is called for each /// ancestor, and invokes this callback as appropriate. /// /// Notifications vary in terms of when they are dispatched. There are two /// main possibilities: dispatch between frames, and dispatch during layout. /// /// For notifications that dispatch during layout, such as those that inherit /// from [LayoutChangedNotification], it is too late to call [State.setState] /// in response to the notification (as layout is currently happening in a /// descendant, by definition, since notifications bubble up the tree). For /// widgets that depend on layout, consider a [LayoutBuilder] instead. final NotificationListenerCallback<T> onNotification; bool _dispatch(Notification notification, Element element) { if (onNotification != null && notification is T) { final bool result = onNotification(notification); return result == true; // so that null and false have the same effect } return false; } @override Widget build(BuildContext context) => child; }
其中属性child是子widget,onNotification是监听到了通知产生的回调。
一个例子:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() => runApp(BuilderApp()); class BuilderApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: NotificationRoute(), ); } } class NotificationRoute extends StatefulWidget { @override NotificationRouteState createState() { return new NotificationRouteState(); } } class NotificationRouteState extends State<NotificationRoute> { String _msg=""; @override Widget build(BuildContext context) { //监听通知 return NotificationListener<MyNotification>( onNotification: (notification) { setState(() { _msg+=notification.msg+" "; }); return true; }, child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ // RaisedButton( // onPressed: () => MyNotification("Hi").dispatch(context), // child: Text("Send Notification"), // ), Builder( builder: (context) { return RaisedButton( //按钮点击时分发通知 onPressed: () => MyNotification("Hi").dispatch(context), child: Text("Send Notification"), ); }, ), Text(_msg) ], ), ), ); } } class MyNotification extends Notification { MyNotification(this.msg); final String msg; }
onNotification
的方法需要返回bool值,返回true,表示当前事件不在向上传递,false表示继续向上传递
进击的小🐴农