我将描述两种方法,但我不会提供代码或示例,因为我认为以可复制粘贴的方式将其放在那里不一定是个好主意 - 我同意@Remi 的评论是,如果您需要在应用程序中执行此操作,则很有可能可以重构应用程序以避免它。但是,有一种方法可以做到这一点 - 尽管被警告,它可能会导致一些问题,例如触摸事件(尽管我认为有办法解决这个问题 - 请参阅 AbsorbPointer and IgnorePointer 了解起点)。由于你还没有真正解释你想要这个做什么,我会假设这不是你需要的。
我鼓励您研究其他方法来做您想做的任何事情,并询问您是否需要帮助找出更好的方法。
不管怎样,继续说好东西 =P:
方法 #1 - 使用现有叠加层:
我自己实际上已经将这种方法用于模式加载指示器,我希望在下方的页面之间被推送时保持该指示器,并且可以从应用程序内的任何位置调用,而无需任何小部件位于其上方的树中。这是一个非常具体的用例,但我认为它证明了这种用法的合理性。
基本上,您想使用叠加层,但您不想创建自己的叠加层(与您正在处理的小部件具有相同的大小),而是要使用现有的叠加层。如果您在应用程序的某个地方使用 MaterialApp、WidgetApp 甚至只是一个 Navigator,那么您已经有了一个几乎可以肯定与屏幕大小相同的 Overlay。如果您有多层叠加层,则希望获得顶部的一层,因为它最有可能覆盖整个屏幕。
要访问它,您可以使用OverlayState rootOverlay = context.rootAncestorStateOfType(const TypeMatcher<OverlayState>()); 来获取根覆盖层(您可能想要断言它确实找到了一个)。
一旦您可以访问它,您就可以创建一个 OverlayEntry 来构建您的任何小部件,然后调用 rootOverlay.insert(...) 来添加它。只要覆盖层本身覆盖整个屏幕(您可以自己进行偏移),您的 OverlayEntry 构建的项目将从左上角定位到屏幕的范围。您还需要确保您在某些时候rootOverlay.remove(...),这意味着保留对 OverlayEntry 的引用。我会亲自创建一个名为 OverlayInsertionManager 的类或跟踪覆盖条目并进行插入/删除的类。
方法 #2 - 使用您自己的小部件
如果您只是在自己的应用程序中执行此操作,我会考虑使用这种方式稍微清洁一些,尽管这可能仍然不是一个好主意。
基本上,您要做的是在您的应用程序中创建一个有状态的小部件 - 高于任何会占用屏幕空间的东西。从理论上讲,这可能意味着您的 MaterialApp/WidgetApp/etc 之上,尽管如果您使用 WidgetApp 提供的主题/文本方向性/等,这可能会给您带来问题。我认为您可以使用WidgetApp.builder 将您的小部件放置在您需要的地方。为方便起见,我们称之为PageOverlay(对应的PageOverlayState。
在您的小部件中,您将拥有一个静态的 of 方法,如下所示(这些在 Flutter 的源代码中随处可见,或多或少是一种约定):
static PageOverlayState of(BuildContext context) {
final PageOverlayState result = context.ancestorStateOfType(const TypeMatcher<PageOverlayState>());
assert(() {
if (result == null) {
throw new FlutterError(
'No Overlay widget found.\n'
);
}
return true;
}());
return result;
}
在您的 PageOverlayState 中,您将有一个类似于 WidgetBuilder _overlayBuidler 的变量,它通常为 null,以及一个类似于 set overlayBuilder(WidgetBuilder overlayBuilder) => setState(() => _overlayBuilder = overlayBuilder);
的方法/设置器
在 PageOverlayState 的构建器中,您将创建一个 Stack;第一个孩子将是您传入WidgetApp.builder 或MaterialApp.builder 的孩子。如果 _overlayBuilder 不为空,您只会创建第二个孩子;如果它不为 null,则第二个孩子应该是 new Builder(builder: _overlayBuilder)。
您可能需要围绕正确调整堆栈大小做一些事情(即将它放在 Expanded 或其他东西中)。