flutter - 如何获取 Widget 的高度?

我不明白如何使用 LayoutBuilder 来获取 Widget 的高度。

我需要显示小部件列表并获取它们的高度,以便计算一些特殊的滚动效果。我正在开发一个包,其他开发人员提供小部件(我不控制它们)。我读到 LayoutBuilder 可以用来获取高度。

在非常简单的情况下,我尝试将 Widget 包装在 LayoutBuilder.builder 中并将其放入 Stack 中,但我总是得到 minHeight 0.0maxHeight INFINITY。我是否误用了 LayoutBuilder?

编辑:看来 LayoutBuilder 是不行的。我找到了CustomSingleChildLayout这几乎是一个解决方案。

我扩展了该委托(delegate),并且能够在 getPositionForChild(Size size, Size childSize) 方法中获取小部件的高度。但是,调用的第一个方法是 Size getSize(BoxConstraints constraints) 并且作为约束,我得到 0 到 INFINITY,因为我将这些 CustomSingleChildLayouts 放置在 ListView 中。

我的问题是 SingleChildLayoutDelegate getSize 的操作就像它需要返回 View 的高度一样。我不知道那个时候 child 的高度。我只能返回constraints.smallest(即0,高度为0),或constraints.biggest,它是无穷大并导致应用程序崩溃。

在文档中甚至说:

...but the size of the parent cannot depend on the size of the child.

这是一个奇怪的限制。

最佳答案

要获取一个小部件在屏幕上的大小/位置,您可以使用 GlobalKey 获取它的 BuildContext 然后找到 RenderBox 的那个特定的小部件,它将包含它的全局位置和渲染大小。

只需注意一件事:如果小部件未呈现,则该上下文可能不存在。这可能会导致 ListView 出现问题,因为小部件仅在它们可能可见时才会呈现。

另一个问题是您在 build 调用期间无法获取小部件的 RenderBox,因为小部件尚未被渲染。


但是如果我需要在构建过程中获取大小怎么办!我能做什么?

有一个很酷的小部件可以提供帮助:Overlay 及其 OverlayEntry。 它们用于在其他所有内容之上显示小部件(类似于堆栈)。

但最酷的是它们在不同的 build 流程上;它们是在 常规小部件之后构建的。

这有一个非常酷的含义:OverlayEntry 的大小可以取决于实际小部件树的小部件。


好的。但是OverlayEntry不需要手动重建吗?

是的,他们有。但是还有一点需要注意:传递给 ScrollableScrollController 是一个类似于 AnimationController 的可监听对象。

这意味着您可以将 AnimatedBuilderScrollController 结合使用,这样可以在滚动时自动重建小部件,效果非常棒。非常适合这种情况,对吧?


将所有内容组合成一个示例:

在以下示例中,您将看到 ListView 内的小部件之后的叠加层并共享相同的高度。

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final controller = ScrollController();
  OverlayEntry sticky;
  GlobalKey stickyKey = GlobalKey();

  @override
  void initState() {
    if (sticky != null) {
      sticky.remove();
    }
    sticky = OverlayEntry(
      builder: (context) => stickyBuilder(context),
    );

    SchedulerBinding.instance.addPostFrameCallback((_) {
      Overlay.of(context).insert(sticky);
    });

    super.initState();
  }

  @override
  void dispose() {
    sticky.remove();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        controller: controller,
        itemBuilder: (context, index) {
          if (index == 6) {
            return Container(
              key: stickyKey,
              height: 100.0,
              color: Colors.green,
              child: const Text("I'm fat"),
            );
          }
          return ListTile(
            title: Text(
              'Hello $index',
              style: const TextStyle(color: Colors.white),
            ),
          );
        },
      ),
    );
  }

  Widget stickyBuilder(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (_,Widget child) {
        final keyContext = stickyKey.currentContext;
        if (keyContext != null) {
          // widget is visible
          final box = keyContext.findRenderObject() as RenderBox;
          final pos = box.localToGlobal(Offset.zero);
          return Positioned(
            top: pos.dy + box.size.height,
            left: 50.0,
            right: 50.0,
            height: box.size.height,
            child: Material(
              child: Container(
                alignment: Alignment.center,
                color: Colors.purple,
                child: const Text("^ Nah I think you're okay"),
              ),
            ),
          );
        }
        return Container();
      },
    );
  }
}

注意:

当导航到不同的屏幕时,调用跟随否则粘滞将保持可见。

sticky.remove();

https://stackoverflow.com/questions/49307677/

相关文章:

flutter - 如何覆盖 Flutter 中的 “Back” 按钮?

user-interface - 如何在 Flutter 中垂直和水平居中文本?

flutter - 如何在 Flutter 中设置按钮的宽度和高度?

angular - NativeScript 与 Flutter

Flutter 在极端情况下对齐两项 - 一项在左侧,一项在右侧

dart - Flutter:小部件构建上的运行方法完成

flutter - 使用不包含 Navigator 的上下文请求的 Navigator 操作

visual-studio-code - 如何为 Flutter 模拟器的 Visual Studi

flutter - 如何根据父级的大小布局小部件?

flutter - 从 StatefulWidget 外部控制状态