【问题标题】:Giving an absolute position to a widget constraint by other widgets由其他小部件为小部件约束提供绝对位置
【发布时间】:2018-04-22 21:02:53
【问题描述】:

我试图在小部件树的绝对位置中提供一个小部件。因为它位于小部件树中的某个位置,所以它的祖先很可能会设置某些布局约束。我正在寻找可以忽略这些约束而只使用绝对坐标的东西。

如果解释令人困惑,我画了一个代表我想要的结果的小图:

我尝试使用Stack 执行此操作,但这使得传递绝对坐标变得困难,即使使用Positioned 也是如此,因为设置属性left: 0.0 将使用祖先的相对坐标。因此,将其设置为零并不一定意味着小部件将位于屏幕的左上角。
我也尝试使用Overlay,但结果与Stack 实现几乎相同。

在 Flutter 中推荐的执行方式是什么?

【问题讨论】:

  • @EricvanderToorn 我做到了,但是要让Positioned 拥有“真实”的绝对坐标,您需要使用它的Stack 才能处于顶层,不是吗?跨度>
  • @EricvanderToorn 而对于“真实”绝对坐标,我的意思是,如果堆栈位于屏幕中心的框内,则坐标 0.0、0.0 不会是屏幕的左上角,但居中框的左上角。
  • 所以你想把它绝对放在你给定的“盒子”内,但忽略任何其他限制对
  • 您能否提供所需行为的 UI 屏幕截图以及最少的代码?这很可能是需要重构的问题。

标签: dart flutter


【解决方案1】:

我将描述两种方法,但我不会提供代码或示例,因为我认为以可复制粘贴的方式将其放在那里不一定是个好主意 - 我同意@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.builderMaterialApp.builder 的孩子。如果 _overlayBuilder 不为空,您只会创建第二个孩子;如果它不为 null,则第二个孩子应该是 new Builder(builder: _overlayBuilder)

您可能需要围绕正确调整堆栈大小做一些事情(即将它放在 Expanded 或其他东西中)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 2020-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多