【问题标题】:Find width of the child widget before build method is invoked again在再次调用 build 方法之前查找子小部件的宽度
【发布时间】:2021-12-30 16:37:12
【问题描述】:

我正在通过组合ElevatedButton 创建一个自定义按钮小部件MyButton,它将包含一个Text 小部件作为子级。它有一个布尔值isLoading 属性,用于配置要构建的按钮类型。当isLoading = true 时,它将返回一个灰色的加载按钮,其宽度与此加载按钮构建之前提供的文本宽度相同。我的问题是如何在 setState 调用或再次调用 build 方法之前获取子 Text 小部件的 width,以便我可以使用该 width 创建相同大小的加载按钮?

在使用子Text 小部件构建默认按钮后,将始终调用加载按钮。 (即isLoading 仅在小部件不是最初重建时才为真)。

代码如下:


class MyButton extends StatefulWidget {
  final String text;
  final bool isLoading;
  final VoidCallback onPressed;
  MyButton({Key key, @required this.text, @required this.isLoading, this.onPressed}) : super(key: key);
  @override
  State<StatefulWidget> createState() => _MyButtonState();
}

class _MyButtonState extends State<MyButton> {
  double _width; // Width of the [Text] child widget that will be used to get the [Container] of same width for loading button

  @override
  void initState() {
    super.initState();
    _width = 150;
  }

  @override
  void didUpdateWidget(covariant MyButton oldWidget) {
    super.didUpdateWidget(oldWidget);
    /*
    Calculate the width....
     */
  }

  @override
  Widget build(BuildContext context) {
    // I want to get the width of this child
    Widget child = Text(
      widget.text,
      style: TextStyle(color: Colors.black),
    );
    if (widget.isLoading) {
      child = Container(
        height: 60,
        width: _width, // this should be same as [Text] width
        color: Colors.grey,
      );
    }
    return ElevatedButton(
      child: child,
      onPressed: !widget.isLoading ? widget.onPressed : null,
      style: ButtonStyle(
        backgroundColor: MaterialStateProperty.all<Color>(
          !widget.isLoading ? Colors.red : Colors.grey,
        ),
      ),
    );
  }
}

这里是我想要做的演示,但是当isLoading = true 是绝对时按钮的大小现在。

我检查了其他帖子和问题,但找不到有用的方法来解决我的用例。使用GlobalKey 是一种解决方案,但不是推荐的方式,使用RenderObject 我无法解决这个问题,因为在这种情况下我们只能获得父级的固有高度和宽度。

我认为除了使用 GlobalKey 和 RenderObject 之外,还有其他方法可以做到这一点。

【问题讨论】:

  • @YeasinSheikh 它使用 globalkey 作为解决方案。我已经提到过,使用 GlobalKey 并不总是推荐的方式。
  • 请再次阅读问题。我已经提到了为什么我不使用这种方式。
  • 您为什么不省点麻烦,使用屏幕尺寸的预定义百分比作为您的宽度呢?与 MediaQuery 一样。
  • 是的,我可以,但我只是想通过将加载按钮设置为相同的宽度来获得相同的视觉按钮尺寸,从而使其更具动态性。
  • 所以你希望当 isLoading true 时你的按钮应该是空白的,颜色应该是灰色的,大小也应该是一样的?

标签: flutter dart button widget renderbox


【解决方案1】:

与其创建一个容器,我更希望您只是隐藏文本,以便按钮的大小与以前相同。试试下面的代码:

Widget build(BuildContext context) {
    return ElevatedButton(
      child: Opacity(
        opacity: !widget.isLoading ? 1 : 0,
        child: Text(
          widget.text,
          style: TextStyle(color: Colors.black),
        ),
      ),
      onPressed: !widget.isLoading ? widget.onPressed : null,
      style: ButtonStyle(
        backgroundColor: MaterialStateProperty.all<Color>(
          !widget.isLoading ? Colors.red : Colors.grey,
        ),
      ),
    );
  }

【讨论】:

  • 谢谢,但它是一种黑客攻击,而不是实际计算尺寸。
  • 根据您的选择,我刚刚提供了在两种情况下保持按钮大小相同的结果。 :)
【解决方案2】:

我们可以使用将postFrameCallback 添加到WidgetBinding 实例来从postFrameCallback 内部的上下文中获取小部件的大小。

注意:这可能不是有效的方法。

这是适用于我的代码。


  @override
  void initState() {
    super.initState();
    getWidth();
    _width = _width ?? 150;
  }

  void getWidth() {
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      if (context?.size is Size) {
        _width = context.size.width;
        print(context.size.toString());
      }
    });
  }

  @override
  void didUpdateWidget(covariant MyButton oldWidget) {
    getWidth();
    super.didUpdateWidget(oldWidget);
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-16
    • 2021-02-08
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 1970-01-01
    • 2012-06-09
    相关资源
    最近更新 更多