Flutter Overlay

公良泰宁
2023-12-01

Overlay 可以实现悬浮组件, 它内部由一个 Stack 构成, 相当于 Android 的 FrameLayout.

用法:

// 创建OverlayEntry
Overlay entry = OverlayEntry(builder:(){/*在这里创建自己的widget*/});
// 往Overlay中插入OverlayEntry
Overlay.of(context).insert(overlayEntry);
// 调用entry自身的remove()方法,从所在的overlay中移除自己
entry.remove();

OverlayEntry builder 参数可以 return Positioned 或者 AnimatedPositioned Widget 在 overlay 中定位自己的位置。

Overlay 继承于 StatefulWidget, Overlay.of(context) 表示向上查找 OverlayState 对象, 使用 OverlayState 对象来进行插入和移除子 widget 的操作. (如何查找? 使用了 InheritedWidget)

  • 可以自定义 Toast 以及其他悬浮组件
  • 以及类似PopupWindow的弹窗效果

分析

WidgetsApp

我们构建 Flutter 时一般都用 MaterialApp/CupertinoApp 作为顶层, 这两个 Widget 的内部包含了 WidgetsApp, 通过查看 WidgetsApp 的源码发现:

GlobalKey<NavigatorState> _navigator;   // <----- 声明
// ...
@override
void initState() {
  super.initState();
  _updateNavigator();                   // <----- 初始化
  // ...
}
// ...
void _updateNavigator() {
  _navigator = widget.navigatorKey ?? GlobalObjectKey<NavigatorState>(this);
}

WidgetsApp 初始化时会创建一个 _navigator , 类型为 GlobalKey<NavigatorState>,而 NavigatorState 就是 Navigator 的状态对象.

Navigator 用于管理页面之间如何跳转,通常也可被称为导航管理,如果用户没有传入navigatorKey,它会自动创建一个.

MaterialApp/CupertinoApp 一般作为 Flutter App 的相对顶层 Widget, 所以每个 App 都会仅有一个用于路由管理的 Navigator 对象.


Navigator

继续到 Navigator 源码里,发现了个 _overlayKey, 类型为 GlobalKey<OverlayState>.

// ...1478行
final GlobalKey<OverlayState> _overlayKey = GlobalKey<OverlayState>();
// ...1576行
OverlayState get overlay => _overlayKey.currentState;
// ...2214行
@override
  Widget build(BuildContext context) {
    // ...
    return Listener(
      onPointerDown: _handlePointerDown,
      onPointerUp: _handlePointerUpOrCancel,
      onPointerCancel: _handlePointerUpOrCancel,
      child: AbsorbPointer(
        absorbing: false,
        child: FocusScope(
          node: focusScopeNode,
          autofocus: true,
          child: Overlay(       // <----- 0.0
            key: _overlayKey,   // <----- ^.^
          ),
        ),
      ),
    );
  }

Navigatorbuild()方法里发现 Navigator 就是使用 Overlay 做子 Widget 的! 在用法那里使用 Overlay.of(context) 获取到的应该就是这个 Overlay 的 State 对象了.


总结

MaterialApp / CupertinoApp 初始化的时候, 会创建一个唯一的 Navigator, Navigator 内部又会创建一个 Overlay.
每个页面都是 Navigator 管理的, 而 Overlay 内部由一个 Stack 构成, 所以 Overlay 可以实现悬浮组件, 让独立的 child widget 悬浮于其他 widget 之上的功能.

 类似资料:

相关阅读

相关文章

相关问答