ProxyWidget
scala
/// 一个拥有子组件(child)的组件,它本身不会去构建新的组件。
///
/// 通常作为其他组件的基类使用,比如 [InheritedWidget] 和 [ParentDataWidget]。
///
/// 参见:
///
/// * [InheritedWidget] ------ 为后代组件提供可读取的环境状态的组件。
/// * [ParentDataWidget] ------ 为子组件的 [RenderObject] 填充 [RenderObject.parentData],
/// 从而配置父组件的布局。
/// * [StatefulWidget] 和 [State] ------ 可以在生命周期内多次构建、变化的组件。
/// * [StatelessWidget] ------ 在给定配置和环境状态下始终以相同方式构建的组件。
/// * [Widget] ------ 总览 Flutter 中所有组件的基类。
abstract class ProxyWidget extends Widget {
/// 创建一个拥有且仅能拥有一个子组件的组件。
const ProxyWidget({super.key, required this.child});
/// 该组件在树中的子组件。
///
/// {@template flutter.widgets.ProxyWidget.child}
/// 此组件只能有一个子组件。
/// 如果要布局多个子组件,请让该组件的 child 使用 [Row]、[Column] 或 [Stack] 之类
/// 拥有 `children` 属性的组件,然后将多个子组件传递给它们。
/// {@endtemplate}
final Widget child;
}
_NotificationElement
scala
/// 一个用于承载 [NotificationListener] 的 Element。
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>;
// 如果监听器提供了 onNotification 回调,并且通知类型匹配 T,
// 则调用回调并返回其结果。
if (listener.onNotification != null && notification is T) {
return listener.onNotification!(notification);
}
// 否则返回 false,表示允许通知继续冒泡。
return false;
}
@override
void notifyClients(covariant ProxyWidget oldWidget) {
// Notification 树不需要去通知客户端。
}
}
方法 onNotification
由 NotifiableElementMixin
提供
NotifiableElementMixin
csharp
/// 将此 mixin 添加到类上,可以接收由子元素分发的 [Notification] 对象。
///
/// 参见:
/// * [NotificationListener] ------ 一个允许消费通知的组件。
mixin NotifiableElementMixin on Element {
/// 当合适类型的通知到达此树中该位置时被调用。
///
/// 返回 true 表示取消通知冒泡;返回 false 表示允许通知继续向上分发到更多的祖先节点。
bool onNotification(Notification notification);
@override
void attachNotificationTree() {
// 绑定通知树节点,将当前元素挂载到父节点的通知树上
_notificationTree = _NotificationNode(_parent?._notificationTree, this);
}
}
_NotificationNode
kotlin
class _NotificationNode {
_NotificationNode(this.parent, this.current);
/// 当前节点,持有实现了 [NotifiableElementMixin] 的 Element。
NotifiableElementMixin? current;
/// 父节点,用于形成通知冒泡链。
_NotificationNode? parent;
/// 分发通知。
///
/// 先交给当前节点的 [onNotification] 处理:
/// - 如果返回 true,表示拦截通知,停止冒泡。
/// - 如果返回 false,表示继续冒泡,则交由父节点处理。
void dispatchNotification(Notification notification) {
if (current?.onNotification(notification) ?? true) {
return;
}
parent?.dispatchNotification(notification);
}
}
🔎 解释:
_NotificationNode
就是一个 链表结构 ,把一层层Element
(实现了NotifiableElementMixin
的,比如NotificationListener
)串联起来。- 当某个子组件调用
notification.dispatch(context)
时,通知会沿着这条链 一层层往上冒泡。 - 在冒泡过程中,每个节点都会调用自己的
onNotification
,决定是否拦截(返回true
)还是继续向上传递(返回false
)。
Element - dispatchNotification
typescript
@override
void dispatchNotification(Notification notification) {
_notificationTree?.dispatchNotification(notification);
}
在 Element
类 里实现的。
这个方法就是 Notification 冒泡的入口。
🔎 整体流程回顾
子组件触发通知
ini
notification.dispatch(context);
Element 转交给 NotificationTree
javascript
void dispatchNotification(Notification notification) {
_notificationTree?.dispatchNotification(notification);
}
Element
不直接处理,而是交给_notificationTree
(也就是_NotificationNode
链表)。
_NotificationNode 遍历
javascript
void dispatchNotification(Notification notification) {
if (current?.onNotification(notification) ?? true) {
return; // 如果返回 true 就拦截
}
parent?.dispatchNotification(notification); // 否则继续往上
}
- 这里的
current
就是_NotificationElement
。
_NotificationElement.onNotification
kotlin
@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;
}
这就是写的 NotificationListener(onNotification: ...)
被调用的地方。