使容器小部件垂直填充父级容器

137

TL;DR 我需要容器填充垂直空间,以便它可以作为触摸监听器。尝试了大多数解决方案,但似乎没有什么起作用的。

所以我想做的是让我的容器在保持固定宽度的同时填满垂直空间。 前两张是现在的情况,第三张是我想要的。我的想法是让容器透明,并具有手势触摸监听器。如果有更好的想法可以提出不同的解决方案。

    Widget build(BuildContext context) {
    return new GestureDetector(
      onHorizontalDragUpdate: _move,
      onHorizontalDragEnd: _handleDragEnd,
      child: new Stack(
        children: <Widget>[
          new Positioned.fill(           
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                new Container(
                  child: new IconButton(                          
                    padding: new EdgeInsets.only(top: 16.0, bottom: 16.0, left: 24.0, right: 24.0),
                    icon: new Icon(Icons.warning),
                    color: Colors.black12,
                    onPressed: () {},
                  )
                ),
              ],
            ),
          ),
          new SlideTransition(
            position: new Tween<Offset>(
              begin:  Offset(0.0, 0.0),
              end: const Offset(-0.6, 0.0),
            ).animate(_animation),
            child: new Card(
              child: new Row(
                children: <Widget>[
                  new Container(
                    width: 20.0,
                    height: 20.0,
                    color: Colors.amber,
                  ),
                  new Expanded(
                    child: new Column(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        
                        _getListTile(),
                        _ifStoplineIsToBeShown()
                      ],
                    ),
                  )
                ],
              )
            ),
          ),
        ],
      )
    );
  }

我相当确定自己错过了什么,因为我尝试了很多不同的方法,但好像没有什么起作用。

我还上传了一个带有调试信息的图像,在这里

PS. 我知道我已将高度设置为固定值,但这是显示容器的唯一方法。


onHorizontalDragStart 没有被调用吗?你的“固定宽度”在哪里? - creativecreatorormaybenot
8个回答

189

诀窍是结合一个 IntrinsicHeight小部件和一个 crossAxisAlignment: CrossAxisAlignment.stretchRow

这将强制使行的子元素在垂直方向上扩展,但行本身将占用最少的垂直空间。

Card(
  child: IntrinsicHeight(
    child: Row(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        Container(
          width: 20.0,
          color: Colors.amber,
        ),
        // Expanded(...)
      ],
    ),
  )
)

6
需要提到IntrinsicHeight会影响性能吗?https://docs.flutter.io/flutter/widgets/IntrinsicHeight-class.html - dazza5000
7
我不这么认为。警告的主要目的是提醒您使用 ConstraintBox 就足够了,而不是使用它。这是预期的使用情况。 - Rémi Rousselet
1
这对我来说并没有填满垂直空间。对我有用的是将“Container.height”设置为“double.infinity”。 - kakyo
这似乎有效 https://stackoverflow.com/a/62358991/491950 - Rob
哇,我以为我的问题无法解决。 - Nikita
显示剩余2条评论

130

使用constraints:BoxConstraints.expand()属性在Container Widget中,可以将容器拉伸到父容器的完整高度。容器将独立于子Widget占据整个空间。

Container(
  color: Colors.green,
  child: Text("Flutter"),
  constraints: BoxConstraints.expand(),
)
请参考链接“Container Cheat sheet” 了解有关容器的更多信息。

8
这个更为简洁,应该使用它来替代已被接受的答案吗? - Nicolas Caous
2
完美解决方案 <3 - STEEL
21
错误提示:BoxConstraints 强制宽度和高度为无限大。 - kapil singh
7
如果容器的父级是Singlechildscrollview(),那么它将无法工作。 - Kamlesh
1
@Kamlesh 是的,我也尝试过了,如果Container的父级是SingleChildScrollView(),这种方法就不起作用。 - Nghien Nghien
显示剩余2条评论

41

只需传入:double.infinity.

如果你想让一个Container填充所有可用空间,你可以直接传入:

width: double.infinity,
height: double.infinity

在Flutter中,子widget不能超过其父widget所施加的“布局约束”。在布局阶段,Flutter引擎使用约束求解器将“越界”值自动更正为其父约束允许的值。如果您有一个大小为50x50的容器,并且为其子元素传入了另一个大小为300x300的容器,则内部容器将被自动更正为“不超过其父级”,因此为50x50。因此,使用足够大的值始终可以确保您“填充父级”。事实上,即使是BoxConstraints.expand()也利用了相同的思想。
  /// Creates box constraints that expand to fill another box constraints.
  ///
  /// If width or height is given, the constraints will require exactly the
  /// given value in the given dimension.
  const BoxConstraints.expand({
    double width,
    double height,
  }) : minWidth = width ?? double.infinity,
       maxWidth = width ?? double.infinity,
       minHeight = height ?? double.infinity,
       maxHeight = height ?? double.infinity;

如果你确定要填充所有空间,你可以直观地传入一个比父元素大(或比整个屏幕大)的数字,如double.infinity


如果您只是简单地模仿Flutter在内部逻辑上的更改,那么它会更有可能破坏您的代码。更好的做法是使用 constraints: BoxConstraints.expand() - user8104581
@andreyrk 谢谢!虽然你的说法通常是正确的,但这里没有风险。Flutter引擎使用约束求解器将更大的值强制转换为其父级允许的值,这是Flutter布局工作原理的最基本原则之一。BoxConstraints.expand()仅仅是利用了同样的事实。我已经更新了我的答案,试图更好地解释它。如果您对这些主题不熟悉,您可能需要了解Flutter引擎在幕后执行布局的方式。 - WSBT
1
这是正确的方式。简单易读,不会在树上添加另一个小部件(至少在您看到的代码中不会)。 - Dave
1
点赞以示解释的价值,谢谢。 - evals
它不起作用 flutter: BoxConstraints 强制宽度和高度为无限。 flutter: 这些无效的约束条件是由以下函数提供给 RenderDecoratedBox 的 layout() 函数的,该函数可能计算了相关的无效约束条件: - undefined

35

4
嗨,我一直在尝试这种方法,但好像不起作用。你能帮忙吗?如果我不设置容器内部的高度,小部件就会消失。 - temporarya
14
默认情况下flex: 1已经是默认值,所以不需要设置。 - Kirill Karmazin
当我尝试在一个带有列的卡片小部件中扩展容器时,这对我很有效。我在卡片的末尾有一个包含材料按钮的容器,我想将其居中在卡片的剩余部分中。没有出现无限问题。谢谢! - M A F
这对我不起作用。 在应用父数据时,抛出了以下断言: ParentDataWidget的使用不正确。ParentDataWidget Expanded(flex:1)希望将FlexParentData类型的ParentData应用于RenderObject,但该RenderObject已设置为接受不兼容类型ParentData的ParentData。通常,这意味着Expanded widget具有错误的祖先RenderObjectWidget。通常,Expanded widgets直接放置在Flex widgets内部。 冒犯的扩展当前放置在IntrinsicHeight widget内部。 - david weng

8

有很多答案建议使用两个事物:

  1. 约束:BoxConstraints.expand(),
  2. 高度:double.infinity,

但是这两个答案都会出现错误信息:

BoxConstraints 强制要求高度无限。

为了避免这种情况,我们可以计算屏幕的高度,具体方法包括以下三部分:

  1. 应用栏
  2. 顶部栏空间(存在于应用栏上方)
  3. 剩余屏幕

1. 获取MediaQuery

 final mediaQuery = MediaQuery.of(context);

2.声明AppBar小部件,Scaffold的AppBar应该使用相同的AppBar实例

final PreferredSizeWidget appBar = AppBar(
      title: Text('Home'),
    );

3. 使用计算出的高度

      Container(
              width: mediaQuery.size.width,
              height: (mediaQuery.size.height -
                  appBar.preferredSize.height -
                  mediaQuery.padding.top),
              color: Colors.red,
            ),

输出:

这里输入图片描述


3
将容器的高度或宽度设置为 double.maxFinite
Container(
   height: double.maxFinite,
    width: 100,)

您可以使您的小部件占据Container小部件的全部大小,然后将容器的高度和/或宽度设置为double.maxFinite。这将使容器采取其父小部件的高度和/或宽度。

2
我建议使用Expanded小部件(它允许我们避免使用IntrinsicHeight小部件),将其与Container的alignment属性相结合,因此即使Container不是屏幕上唯一的小部件,它也可以正常工作。
Expanded(
  child: Container(
    alignment: Alignment.center,
    child: Text('Your text', textAlign: TextAlign.center))),

这样做还可以避免应用程序崩溃的风险,当您意外地将小部件树的某些部分无限水平和垂直扩展时,会经常发生这种情况(这就是为什么在许多情况下不能使用BoxConstraints小部件的原因)。
关于在Flutter中传递约束的问题,可以在这里阅读更多内容 - 必读文章:https://medium.com/flutter-community/flutter-the-advanced-layout-rule-even-beginners-must-know-edc9516d1a2

1

这项工作对我来说很有效

height: MediaQuery.of(context).size.height,

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接