需求1:在Widget初始化后就发送一次通知
需求2:通知中需要携带Size作为数据
分析:flutter库里有一个SizeChangedLayoutNotification及与其配合工作的SizeChangedLayoutNotifier、_RenderSizeChangedWithCallback ,源码如下。
class SizeChangedLayoutNotification extends LayoutChangedNotification { }
class SizeChangedLayoutNotifier extends SingleChildRenderObjectWidget {
const SizeChangedLayoutNotifier({
Key key,
Widget child,
}) : super(key: key, child: child);
@override
_RenderSizeChangedWithCallback createRenderObject(BuildContext context) {
return _RenderSizeChangedWithCallback(
onLayoutChangedCallback: () {
SizeChangedLayoutNotification().dispatch(context);
}
);
}
}
class _RenderSizeChangedWithCallback extends RenderProxyBox {
_RenderSizeChangedWithCallback({
RenderBox child,
@required this.onLayoutChangedCallback,
}) : assert(onLayoutChangedCallback != null),
super(child);
final VoidCallback onLayoutChangedCallback;
Size _oldSize;
@override
void performLayout() {
super.performLayout();
// Don't send the initial notification, or this will be SizeObserver all
// over again!
if (_oldSize != null && size != _oldSize)
onLayoutChangedCallback();
_oldSize = size;
}
}
但SizeChangedLayoutNotification 在Widget第一次build完成时并不会发送通知,因此需要对_RenderSizeChangedWithCallback的performLayout进行改造。
@override
void performLayout() {
super.performLayout();
//在第一次layout结束后就会进行通知
if (size != _oldSize)
onLayoutChangedCallback(size.height);
_oldSize = size;
}
同时,为了能将Widget的Size连同通知一起发送出去,需要自定义Notification及Callback。
class NewSizeChangedLayoutNotification extends LayoutChangedNotification{
Size size;
NewSizeChangedLayoutNotification(this.size);
}
class NewSizeChangedLayoutNotifier extends SingleChildRenderObjectWidget {
const NewSizeChangedLayoutNotifier({
Key key,
Widget child,
}) : super(key: key, child: child);
@override
_NewRenderSizeChangedWithCallback createRenderObject(BuildContext context) {
return _NewRenderSizeChangedWithCallback(
onLayoutChangedCallback: (Size size) {
NewSizeChangedLayoutNotification(size).dispatch(context);
}
);
}
}
typedef VoidCallbackWithParam = Function(Size size);
class _NewRenderSizeChangedWithCallback extends RenderProxyBox {
_NewRenderSizeChangedWithCallback({
RenderBox child,
@required this.onLayoutChangedCallback,
}) : assert(onLayoutChangedCallback != null),
super(child);
final VoidCallbackWithParam onLayoutChangedCallback;
Size _oldSize;
@override
void performLayout() {
super.performLayout();
//在第一次layout结束后就会进行通知
if (size != _oldSize)
onLayoutChangedCallback(size);
_oldSize = size;
}
}
调用:
NotificationListener(
onNotification: (notification){
print(notification.size.toString());
return true;
},
child: NewSizeChangedLayoutNotifier(
child: Container(),
),
)
打完,收工。