如何根据父容器的大小布局小部件?

132

假设您有一个父小部件,它可能具有可变大小。

例如:

var container = new Container(
   height: 200.0, // Imagine this might change
   width: 200.0, // Imagine this might change
   // Imagine content in this container will 
   // depend on the parent container
   child: new Container(), 
);

也许您希望父容器的子代根据其所给出的大小呈现不同的内容。

想一想响应式设计断点,如果宽度超过X,则使用此布局,如果宽度小于X,则使用那个布局。

Flutter中如何最好地实现这个功能?


Flutter Wiki提供了几种方法来创建响应式应用程序:https://github.com/flutter/flutter/wiki/Creating-Responsive-Apps - Aaron
5个回答

221

您需要使用 LayoutBuilder 小部件,该小部件将在布局时构建,并提供父级小部件的约束条件。

LayoutBuilder 接受一个 build() 函数,其中包括标准的 BuildContextBoxConstraints 作为参数,可以帮助根据大小动态渲染小部件。

让我们构建一个简单的示例小部件,如果父级宽度大于200px,则呈现“LARGE”,如果父级宽度小于等于200px,则呈现“SMALL”。

var container = new Container(
  // Toggling width from 100 to 300 will change what is rendered
  // in the child container
  width: 100.0,
  // width: 300.0
  child: new LayoutBuilder(
    builder: (BuildContext context, BoxConstraints constraints) {
      if(constraints.maxWidth > 200.0) {
        return new Text('BIG');
      } else {
        return new Text('SMALL');
      }
    }
  ),
);

1
如果小部件需要宽度和高度怎么办?我该如何将其设置为父元素的大小? - Dpedrinha
9
除了约束和大小不同之外,这很棒。当您尝试在 Scrollable 中获取小部件的大小时,这一点变得明显。如果您有一个 ListView 并尝试获取其中一个子项的垂直约束,则会得到 maxHeight 为 double.infinity 和 minHeight 为 0.0。 - ThinkDigital
哎呀!非常感谢。 - Rajesh
if语句中的代码从未被调用,那么这个程序是如何工作的? - 68060
1
请注意,width: 300.0 被注释掉了,所以如果你取消注释这一行(即将宽度从100更改为300),if语句将被调用。 - satvikpendem
显示剩余2条评论

10
将小部件放入容器中,并将其宽度和/或高度设置为 double.maxFinite
示例:
 child: Container(
     width: double.maxFinite,
   )

这确实非常有用。谢谢你。 - jsonx
这到底是做什么的呢? - Luke Hutchison

5

我遇到了一个有趣的情况,我的父子组件根据内容(包含描述的文本)动态增加大小。这个父组件以只读模式显示内容,但这个解决方案可能也可以解决其他需要动态增加文本框高度的问题。

我使用了一个height变量和一个GlobalKey。在小部件的initState中,我使用了SchedulerBinding,它会在布局构建后运行其addPostFrameCallback 方法。

将globalKey分配给任何需要其子节点高度的父部件。

double height = 0.0;
GlobalKey _globalKey = GlobalKey();

  @override
  void initState() {
    SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
      height = _globalKey.currentContext.size.height;
      print('the new height is $height');
      setState(() {});
    });
    super.initState();
  }

其余的代码看起来像这样

// this parent having dynamic height based on content 
Container(
  width: 100.0,
  key: _globalKey,
  child: Container(
    width: 100.0,
    child: Row(children: [  ///  you can have column as well or any other widget. 
      Container(child: ...),
      Container(height: height,), ///this widget will take height from parent 
    ],),
  )
)

你知道如果我有许多消息气泡而不仅仅是一个,我该如何使用它吗? - scott lee
1
@scottlee 很有趣的问题,我正在努力解决 :)。我需要它来处理评论。我猜解决方案是将该气泡作为单独的小部件,并使用StreamBuilder会有所帮助。一旦你知道小部件的构建完成,你就可以通过StreamBuilder将高度发送到特定的小部件。我相信这会有所帮助。 - Muhammad Adil
@scottlee 我已经尝试过了,它完美地运行了。让我知道你是如何处理的,也许我可以提供一个解决方案。 - Muhammad Adil

1
您可以尝试使用IntrinsicHeight widget:

https://api.flutter.dev/flutter/widgets/IntrinsicHeight-class.html

对我来说,这是最简单的解决方案。但它似乎很昂贵,因此在可能的情况下应该避免使用。

var container = Container(
height: 200.0, // Imagine this might change
width: 200.0, // Imagine this might change

child: IntrinsicHeight(
      child: Container()), 
);

-20

使用以下代码动态设置小部件的大小以适应父级:

Container(
  color: Colors.red,
  alignment: Alignment.center,
  child: Wrap(children: <Widget>[

    GestureDetector(
      child: Text(
        'Button',
        style: TextStyle(
            color: Color(0xff0079BF), fontSize:20),
      ),
      onTap: () {


        Navigator.pushReplacementNamed(context, '/signin');
      },
    ),


    Text(
      'You have pushed the button this many times:',
      style: TextStyle(fontSize: 50),
    ),

  ]),
)

我希望这个解决方案对你有用。


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