如何在Flutter中将ListView添加到列中?


125

我正在尝试为Flutter应用程序构建一个简单的登录页面。我已经成功构建了TextFields和Login / Signin按钮。我想添加一个水平ListView。当我运行代码时,我的元素消失了,如果我在没有ListView的情况下做到了,那也很好。如何正确执行此操作?

return new MaterialApp(
        home: new Scaffold(
          appBar: new AppBar(
            title: new Text("Login / Signup"),
          ),
          body: new Container(
            child: new Center(
              child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  new TextField(
                    decoration: new InputDecoration(
                      hintText: "E M A I L    A D D R E S S"
                    ),
                  ),
                  new Padding(padding: new EdgeInsets.all(15.00)),
                  new TextField(obscureText: true,
                    decoration: new InputDecoration(
                      hintText: "P A S S W O R D"
                    ),
                    ),
                  new Padding(padding: new EdgeInsets.all(15.00)),
                  new TextField(decoration: new InputDecoration(
                    hintText: "U S E R N A M E"
                  ),),
                  new RaisedButton(onPressed: null,
                  child:  new Text("SIGNUP"),),
                  new Padding(padding: new EdgeInsets.all(15.00)),
                  new RaisedButton(onPressed: null,
                  child: new Text("LOGIN"),),
                  new Padding(padding: new EdgeInsets.all(15.00)),
                  new ListView(scrollDirection: Axis.horizontal,
                  children: <Widget>[
                    new RaisedButton(onPressed: null,
                    child: new Text("Facebook"),),
                    new Padding(padding: new EdgeInsets.all(5.00)),
                    new RaisedButton(onPressed: null,
                    child: new Text("Google"),)
                  ],)

                ],
              ),
            ),
            margin: new EdgeInsets.all(15.00),
          ),
        ),
      );

Answers:


74

您可以检查控制台输出。它显示错误:

在performResize()期间引发了以下断言:水平视口的高度不受限制。视口在横轴上扩展以填充其容器,并约束其子代以使其在横轴上的范围匹配。在这种情况下,将为水平视口提供无限量的垂直空间以进行扩展。

您需要在水平列表中添加高度限制。例如,将容器包装成高度:

Container(
  height: 44.0,
  child: ListView(
    scrollDirection: Axis.horizontal,
    children: <Widget>[
      RaisedButton(
        onPressed: null,
        child: Text("Facebook"),
      ),
      Padding(padding: EdgeInsets.all(5.00)),
      RaisedButton(
        onPressed: null,
        child: Text("Google"),
      )
    ],
  ),
)

6
接下来的两个答案给出了另外两个解决方案,并说明了正在发生的事情。
pashute

299

我也有这个问题。我的解决方案是使用Expanded小部件扩展剩余空间。

new Column(
  children: <Widget>[
    new Expanded(
      child: horizontalList,
    )
  ],
);

2
这是一个很好的解决方案,因为它允许ListView的大小可变的高度/宽度,例如当您希望它仅占用剩余空间时。当您很难知道确切的高度/宽度时,它可以让您考虑屏幕尺寸的变化。
丹尼尔·艾伦

1
这应该是公认的答案。此解决方案使ListView可以处理屏幕的其余部分,而不必处理媒体查询。
特伦斯·庞塞

对于Flutter来说,我太陌生了,不知道为什么能行,但是我很高兴它能行。谢谢。Flutter的错误消息对非专家解释此问题的根本原因不是很有帮助。
devdanke

谢谢,您的回答节省了我的时间。
Licat Julius

126

错误原因:

Column会在主轴方向(垂直轴)上扩展到最大尺寸,因此也会扩展ListView

解决方案

因此,您需要限制的高度ListView。这样做的方法很多,您可以选择最适合自己的需求。


  1. 如果要允许ListView占用内部Column使用的所有剩余空间Expanded

    Column(
      children: <Widget>[
        Expanded(
          child: ListView(...),
        )
      ],
    )
    

  1. 如果您想将限制ListView某些height,您可以使用SizedBox

    Column(
      children: <Widget>[
        SizedBox(
          height: 200, // constrain height
          child: ListView(),
        )
      ],
    )
    

  1. 如果您ListView很小,则可以尝试shrinkWrap在其上使用物业。

    Column(
      children: <Widget>[
        ListView(
          shrinkWrap: true, // use it
        )
      ],
    )
    

我的身高不应该固定,其他答案对我也不起作用= /
Daniel Vilela

1
@DanielVilela选项1应该适合您。如果没有,请将其发布为问题,如果有空我可以回答。
CopsOnRoad

1
我知道了!谢谢。我必须在某些战略位置放置Expanded()。
丹尼尔·维拉

谢谢,我没有考虑扩展。
吉尔万·安德烈

感谢收缩包装:在ListView()中为true
Rana Hyder

18

我有SingleChildScrollView一个父母,一个Column小部件,然后将列表视图小部件作为最后一个孩子。

在列表视图中添加这些属性对我有用。

  physics: NeverScrollableScrollPhysics(),
  shrinkWrap: true,
  scrollDirection: Axis.vertical,

14

扩展小部件会利用可用空间尽可能地增加它的大小。由于ListView本质上具有无限的高度,因此会导致错误。

 Column(
  children: <Widget>[
    Flexible(
      child: ListView(...),
    )
  ],
)

在这里,我们应该使用“灵活”窗口小部件,因为即使没有足够的窗口小部件来全屏显示,它也只会占用“展开”全屏显示所需的空间。


10

实际上,当您阅读文档时,ListView应该位于Expanded Widget内,这样它才能工作。

  Widget build(BuildContext context) {
return Scaffold(
    body: Column(
  children: <Widget>[
    Align(
      child: PayableWidget(),
    ),
    Expanded(
      child: _myListView(context),
    )
  ],
));

}


7

正如上面其他人提到的那样,用Expanded包装列表视图是解决方案。

但是,当您处理嵌套的Columns时,还需要将ListView限制为一定的高度(很多时候面对这个问题)。

如果有人有其他解决方案,请在评论中提及或添加答案。

  SingleChildScrollView(
   child: Column(
     children: <Widget>[
       Image(image: ),//<< any widgets added
       SizedBox(),
       Column(
         children: <Widget>[
           Text('header'),  //<< any widgets added
            Expanded(child: 
            ListView.builder(
              //here your code
               scrollDirection: Axis.horizontal,
        itemCount: items.length,
        itemBuilder: (BuildContext context, int index) {
            return Container();
                   } 
         )
        ),
        Divider(),//<< any widgets added
         ],
       ),

     ],
   ), 
  );

嵌套列中不使用扩展,仅使用shrikWrap:true,物理:listView中的NeverScrolPhysics()属性
Mohamed Kamel

5

您可以使用FlexFlexible小部件。例如:

Flex(
direction: Axis.vertical,
children: <Widget>[
    ... other widgets ...
    Flexible(
        flex: 1,
        child: ListView.builder(
        itemCount: ...,
        itemBuilder: (context, index) {
            ...
        },
        ),
    ),
],

);


0
return new MaterialApp(
    home: new Scaffold(
      appBar: new AppBar(
        title: new Text("Login / Signup"),
      ),
      body: new Container(
        child: new Center(
          child: ListView(
          //mainAxisAlignment: MainAxisAlignment.center,
          scrollDirection: Axis.vertical,
            children: <Widget>[
              new TextField(
                decoration: new InputDecoration(
                  hintText: "E M A I L    A D D R E S S"
                ),
              ),
              new Padding(padding: new EdgeInsets.all(15.00)),
              new TextField(obscureText: true,
                decoration: new InputDecoration(
                  hintText: "P A S S W O R D"
                ),
                ),
              new Padding(padding: new EdgeInsets.all(15.00)),
              new TextField(decoration: new InputDecoration(
                hintText: "U S E R N A M E"
              ),),
              new RaisedButton(onPressed: null,
              child:  new Text("SIGNUP"),),
              new Padding(padding: new EdgeInsets.all(15.00)),
              new RaisedButton(onPressed: null,
              child: new Text("LOGIN"),),
              new Padding(padding: new EdgeInsets.all(15.00)),
              new ListView(scrollDirection: Axis.horizontal,
              children: <Widget>[
                new RaisedButton(onPressed: null,
                child: new Text("Facebook"),),
                new Padding(padding: new EdgeInsets.all(5.00)),
                new RaisedButton(onPressed: null,
                child: new Text("Google"),)
              ],)

            ],
          ),
        ),
        margin: new EdgeInsets.all(15.00),
      ),
    ),
  );

-1

尝试使用Sliver:

Container(
    child: CustomScrollView(
      slivers: <Widget>[
        SliverList(
          delegate: SliverChildListDelegate(
            [
              HeaderWidget("Header 1"),
              HeaderWidget("Header 2"),
              HeaderWidget("Header 3"),
              HeaderWidget("Header 4"),
            ],
          ),
        ),
        SliverList(
          delegate: SliverChildListDelegate(
            [
              BodyWidget(Colors.blue),
              BodyWidget(Colors.red),
              BodyWidget(Colors.green),
              BodyWidget(Colors.orange),
              BodyWidget(Colors.blue),
              BodyWidget(Colors.red),
            ],
          ),
        ),
        SliverGrid(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
          delegate: SliverChildListDelegate(
            [
              BodyWidget(Colors.blue),
              BodyWidget(Colors.green),
              BodyWidget(Colors.yellow),
              BodyWidget(Colors.orange),
              BodyWidget(Colors.blue),
              BodyWidget(Colors.red),
            ],
          ),
        ),
      ],
    ),
  ),
)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.