Flutter Notification 自底向上的数据传递
Flutter Notification 自底向上的数据传递
Notification和InheritedWidget作用相反,InheritedWidget是自上向下传递数据,Notification是自下向上传递数据.
NotificationListener
NotificationListener的代码很简单,只有一个方法,onNotification,处理通知事件,并通过返回布尔值来决定该事件是否继续向上传递,这个方法需要用户自定义.
onNotification
final NotificationListenerCallback<T>? onNotification;
Notification
Notification也只有一个方法dispatch.
dispatch的方法很简单,就是调用传入BuildContext的dispatchNotification方法.
void dispatch(BuildContext? target) {
target?.dispatchNotification(this);
}
下面看一下dispatchNotification方法.它是调用了_notificationTree的dispatchNotification方法。
@override
void dispatchNotification(Notification notification) {
_notificationTree?.dispatchNotification(notification);
}
_notificationTree是每个element都有的一个对象,这里看一下它的初始化。正常是赋值了父element的_notificationTree对象.
void attachNotificationTree() {
_notificationTree = _parent?._notificationTree;
}
但是要是element添加了NotifiableElementMixinmixin,它就会创建一个新的_NotificationNode
mixin NotifiableElementMixin on Element {
bool onNotification(Notification notification);
@override
void attachNotificationTree() {
_notificationTree = _NotificationNode(_parent?._notificationTree, this);
}
}
而NotificationListener组件的element就添加了这个NotifiableElementMixinmixin
const NotificationListener({
super.key,
required super.child,
this.onNotification,
});
final NotificationListenerCallback<T>? onNotification;
@override
Element createElement() {
return _NotificationElement<T>(this);
}
}
class _NotificationElement<T extends Notification> extends ProxyElement with NotifiableElementMixin {
_NotificationElement(NotificationListener<T> super.widget);
@override
bool onNotification(Notification notification) {
final NotificationListener<T> listener = widget as NotificationListener<T>;
if (listener.onNotification != null && notification is T) {
return listener.onNotification!(notification);
}
return false;
}
@override
void notifyClients(covariant ProxyWidget oldWidget) {
// Notification tree does not need to notify clients.
}
}
从这里我们可以推断出每一层NotificationListener它都有一个属于自己的_NotificationNode它的作用就是可以判断是否要继续向上通知。看到这里我们应该明白了_notificationTree是怎么生成的,我们再来看一下它的是怎么向上通知的。_notificationTree会调用自身的dispatchNotification方法,这个方法会调用onNotification方法。
void dispatchNotification(Notification notification) {
if (current?.onNotification(notification) ?? true) {
return;
}
parent?.dispatchNotification(notification);
}
而这里它则是调用了上面_NotificationElement的onNotification方法,这里调用的就是NotificationListener里我们实现的onNotification方法,不过它会先判断我们的范型是否一致,要是范型一致的话就调用,不一致的话就继续调用父组件的dispatchNotification方法。
@override
bool onNotification(Notification notification) {
final NotificationListener<T> listener = widget as NotificationListener<T>;
if (listener.onNotification != null && notification is T) {
return listener.onNotification!(notification);
}
return false;
}
SizeChangedLayoutNotification
这是一个监听组件Size改变的Notification,比如我们想在父组件获取子组件的大小就可以用这个.
下面的代码是在官方的SizeChangedLayoutNotifier加了一些修改.
class SizeChangedLayoutNotification extends Notification {
final Size size;
SizeChangedLayoutNotification(this.size);
}
class SizeChangedLayoutNotifier extends SingleChildRenderObjectWidget {
const SizeChangedLayoutNotifier({
Key key,
Widget child,
}) : super(key: key, child: child);
@override
_RenderSizeChangedWithCallback createRenderObject(BuildContext context) {
return _RenderSizeChangedWithCallback(
onLayoutChangedCallback: (Size size) {
SizeChangedLayoutNotification(size).dispatch(context);
}
);
}
}
class _RenderSizeChangedWithCallback extends RenderProxyBox {
_RenderSizeChangedWithCallback({
RenderBox child,
@required this.onLayoutChangedCallback,
}) : assert(onLayoutChangedCallback != null),
super(child);
final ValueChanged<Size> onLayoutChangedCallback;
Size _oldSize;
@override
void performLayout() {
super.performLayout();
if (size != _oldSize)
onLayoutChangedCallback(size);
_oldSize = size;
}
}
使用代码.这里只做演示,SizeChangedLayoutNotification和官方的重名了,官方的widget是只发通知,不会传递size,如果想实际使用下面的代码,要先改一下组件的名称.
NotificationListener<SizeChangedLayoutNotification>(
onNotification: (SizeChangedLayoutNotification notification) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
childSize = notification.size;
});
});
return true;
},
child: SizeChangedLayoutNotifier(
child: child
),
)
每当子child大小发生改变的时候我们就会收到SizeChangedLayoutNotification的通知.
转载自:https://juejin.cn/post/6911233021320364039