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

How to add a ListView to a Column in Flutter?

我正在尝试为我的 Flutter 应用构建一个简单的登录页面。我已成功构建 TextFields 并在按钮中记录 in/Sign。我想添加一个水平的 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),
          ),
        ),
      );

您可以检查控制台输出。它打印错误:

The following assertion was thrown during performResize(): The horizontal viewport was given unbounded height. Viewports expand in the cross axis to fill their container and constrain their children to match their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of vertical space in which to expand.

您需要为水平列表添加高度限制。例如。用高度包裹在 Container 中:

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"),
      )
    ],
  ),
)

我也遇到了这个问题。我的解决方案是使用 Expanded 小部件来扩展 remain space.

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

错误原因:

Column在主轴方向(垂直轴)扩展到最大尺寸,ListView.

也是如此

解决方案:

因此,您需要限制 ListView 的高度。有很多种方法,您可以选择最适合您需要的方法。


  1. 如果要让ListView占用Column内所有剩余的space,使用Expanded.

    Column(
      children: <Widget>[
        Expanded( //        <-- Use 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, // Set this
        )
      ],
    )
    

  1. 如果你想让 ListView 尽可能小,使用 FlexibleListView.shrinkWrap:

    Column(
      children: <Widget>[
        Flexible( //        <-- Use Flexible 
          child: ListView(
            shrinkWrap: true, // and set this
          ),
        )
      ],
    )
    

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

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

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

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

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

}

正如上面其他人所提到的,用 Expanded 包装 listview 是解决方案。

但是当你处理嵌套的 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
         ],
       ),

     ],
   ), 
  );

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

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

);

Expanded Widget 在 space 可用的情况下尽可能地增加其大小,因为 ListView 本质上具有无限高度,因此会导致错误。

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

这里我们应该使用 Flexible 小部件,因为即使没有足够的小部件在全屏上呈现,它也只会将 space 所需的 space 展开为全屏。

尝试使用裂片:

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),
            ],
          ),
        ),
      ],
    ),
  ),
)
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),
      ),
    ),
  );

这是一个非常简单的方法。有不同的获取方式,可以通过ExpandedSizedboxContainer获取,根据需要使用。

  1. 使用 Expanded :扩展 RowColumnFlex 的子项的小部件,以便子项填充可用的space.

    Expanded(
        child: ListView(scrollDirection: Axis.horizontal,
            children: <Widget>[
              OutlineButton(onPressed: null,
                  child: Text("Facebook")),
              Padding(padding: EdgeInsets.all(5.00)),
              OutlineButton(onPressed: null,
                  child: Text("Google")),
              Padding(padding: EdgeInsets.all(5.00)),
              OutlineButton(onPressed: null,
                  child: Text("Twitter"))
            ]),
      ),
    

使用 Expanded 小部件可以使 RowColumnFlex 的子部件沿主轴扩展以填充可用的 space (例如,水平表示行或垂直表示列)。

  1. 使用 SizedBox : 指定大小的框。

    SizedBox(
        height: 100,
        child: ListView(scrollDirection: Axis.horizontal,
            children: <Widget>[
              OutlineButton(
                  color: Colors.white,
                  onPressed: null,
                  child: Text("Amazon")
              ),
              Padding(padding: EdgeInsets.all(5.00)),
              OutlineButton(onPressed: null,
                  child: Text("Instagram")),
              Padding(padding: EdgeInsets.all(5.00)),
              OutlineButton(onPressed: null,
                  child: Text("SoundCloud"))
            ]),
     ),
    

如果给定一个子项,此小部件会强制其子项具有特定的宽度 and/or 高度(假设此小部件的父项允许值)。

  1. 使用Container : 一个方便的小部件,结合了常见的绘画定位调整大小 个小部件。

     Container(
        height: 80.0,
        child: ListView(scrollDirection: Axis.horizontal,
            children: <Widget>[
              OutlineButton(onPressed: null,
                  child: Text("Shopify")),
              Padding(padding: EdgeInsets.all(5.00)),
              OutlineButton(onPressed: null,
                  child: Text("Yahoo")),
              Padding(padding: EdgeInsets.all(5.00)),
              OutlineButton(onPressed: null,
                  child: Text("LinkedIn"))
            ]),
      ),
    

所有三个的输出都是这样的

  Column(
    children: <Widget>[
      Text('Leading text widget'),
      ListView(
        shrinkWrap: true,
        physics: NeverScrollableScrollPhysics(),
        children: <Widget>[
          ListTile(
            leading: Icon(Icons.map),
            title: Text('Map'),
          ),
          ListTile(
            leading: Icon(Icons.photo_album),
            title: Text('Album'),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text('Phone'),
          ),
        ],
      ),
      Text('More widget'),
    ],
  );

只需使用

shrinkWrap: true,

physics: NeverScrollableScrollPhysics(),

listView 中的属性

此外,您可以尝试使用 CustomScrollView

CustomScrollView(
      controller: _scrollController,
      slivers: <Widget>[
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              final OrderModel order = _orders[index];

              return Container(
                margin: const EdgeInsets.symmetric(
                  vertical: 8,
                ),
                child: _buildOrderCard(order, size, context),
              );
            },
            childCount: _orders.length,
          ),
        ),
        SliverToBoxAdapter(
          child: _buildPreloader(context),
        ),
      ],
    );

提示:_buildPreloaderreturnCircularProgressIndicatorText

在我的例子中,我想在 ListView 下显示一些小部件。使用 Column 对我不起作用,因为列内 ListView 周围的小部件始终在屏幕上显示为“向上”,例如“绝对位置”

抱歉我的英语不好

你需要做两件事:

  • Column 包裹在 SingleChildScrollView
  • ListView
  • 中添加shrinkWrap: truephysics: NeverScrollableScrollPhysics()

为什么有效:

据我所知,NeverScrollableScrollPhysics 禁用 ListView 的滚动。 因此,滚动适用于 SingleChildScrollView。 如果我错了,请在下方评论。

SingleChildScrollView(
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text('Filter'),
      ListView.separated(
        shrinkWrap: true,
        physics: NeverScrollableScrollPhysics(),
        itemCount: rides.length,
        itemBuilder: (BuildContext context, int index) {
          # return some widget
        }
      ),

[解决方案预览] - [列表项可滚动但标题固定]

我有非常小而直接的答案,看到将 listview 放在列中会强制列无限扩展,这基本上是一个错误。

现在,如果你像其他人建议的那样把 physics: NeverScrollableScrollPhysics(), 放在列表视图中,那么如果你禁用其中的滚动,那么使用列表视图有什么意义..

有一个简单的修复方法,坦率地说,我是通过点击和试验找到的。让我在代码后给你一个小解释。

Column(
      children: [
        Text(
          "All Bookings",
          style: TextStyle(fontSize: 20, fontWeight: FontWeight.w600, color: Colors.brown[700]),
        ),
        Expanded(
          child: Container(
            margin: EdgeInsets.only(top: 24),
            child: ListView.builder(
              itemCount: 30,
              itemBuilder: (BuildContext context, int index) => ListTile(
                title: Text("List Item ${index + 1}"),
              ),
            ),
          ),
        ),
      ],
    )

我要求在 Column 中将标题作为第一个元素,然后放置一个 Listview 以便用户可以滚动列表。这是一种通用的要求。您也可以将它放在底部 Sheet 或模式中。

代码解释:

  1. 我保留第一个 child 作为列内的标题 ok(我不想滚动,我希望它被修复)
  2. 我在列中扩展了child,这就像获取列中所有“剩余的space”。
  3. 我在其中保留了容器(只是为了在标题和列表视图之间放置一些 space 带边距)这是可选的,您可以删除容器,它仍然有效。
  4. 现在 Listview 受到很好的约束,不会尝试在列中无限拉伸。由于 Expanded 小部件已经对其进行了约束。

如果我有任何错误或者此代码不起作用(它现在可以正常工作:)

,请纠正我

就我而言,我使用的是

  • singleChildScrollView
  • 容器
  • 未来建设者 - 列表视图

我想用整列滚动最后一个滚动视图 为此添加

physics: NeverScrollableScrollPhysics(),

列表视图中的这一行。

用展开的小部件包装您的列表视图