这是我的代码:

@override
Widget build(BuildContext context) {
  return new Material(
    color: Colors.deepPurpleAccent,
    child: new Column(
     mainAxisAlignment: MainAxisAlignment.center,
        children:<Widget>[new GridView.count(crossAxisCount: _column,children: new List.generate(_row*_column, (index) {
          return new Center(
              child: new CellWidget()
          );
        }),)]
    )
  );
}

例外情况如下:

I/flutter ( 9925): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 9925): The following assertion was thrown during performResize():
I/flutter ( 9925): Vertical viewport was given unbounded height.
I/flutter ( 9925): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter ( 9925): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter ( 9925): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter ( 9925): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter ( 9925): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter ( 9925): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter ( 9925): the height of the viewport to the sum of the heights of its children.
I/flutter ( 9925): 
I/flutter ( 9925): When the exception was thrown, this was the stack:
I/flutter ( 9925): #0      RenderViewport.performResize.<anonymous closure> (package:flutter/src/rendering/viewport.dart:827:15)
I/flutter ( 9925): #1      RenderViewport.performResize (package:flutter/src/rendering/viewport.dart:880:6)
I/flutter ( 9925): #2      RenderObject.layout (package:flutter/src/rendering/object.dart:1555:9)

不要使用Column进行单子对齐。使用Align代替。

new Align(
  alignment: Alignment.topCenter,
  child: new GridView(),
)

将网格视图放置在Flexible或Expanded小部件内

return new Material(
    color: Colors.deepPurpleAccent,
    child: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children:<Widget>[
         Flexible(
          child:  GridView.count(crossAxisCount: _column,children: new List.generate(_row*_column, (index) {
          return new Center(
             child: new CellWidget(),
          );
        }),))]
    )
);

加上这两行

ListView.builder(
    scrollDirection: Axis.vertical,
    shrinkWrap: true,
...

这通常发生在你试图在一个列中使用一个ListView/GridView时,有很多方法来解决它,我在这里列出了几个。

将ListView包装为Expanded 列( 孩子们:<部件> ( Expanded(// wrap in Expanded . 孩子:列表视图(…), ), ), ) 在sizebox中包装ListView并给出一个有界的高度 列( 孩子们:<部件> ( SizedBox ( 高度:400,//固定高度 孩子:列表视图(…), ), ), ) 在ListView中使用shrinkWrap: true。 列( 孩子们:<部件> ( 列表视图( shrinkWrap: true, //使用这个 ), ), )


有一个名为Center的小部件。它应该帮助你实现你想做的事情(垂直居中)。中心小部件的正式文档


所以,每个人都上传了答案,但没有人愿意解释原因: 我将复制关于shrinkWrap的文档:

Whether the extent of the scroll view in the [scrollDirection] should be determined by the contents being viewed. If the scroll view does not shrink wrap, then the scroll view will expand to the maximum allowed size in the [scrollDirection]. If the scroll view has unbounded constraints in the [scrollDirection], then [shrinkWrap] must be true. Shrink wrapping the content of the scroll view is significantly more expensive than expanding to the maximum allowed size because the content can expand and contract during scrolling, which means the size of the scroll view needs to be recomputed whenever the scroll position changes. Defaults to false.

所以,从文档的词汇表来看,这里发生的是我们的ListView处于一个无限约束的情况(在我们滚动的方向上),因此ListView会抱怨:

... 垂直视口被赋予无限的垂直空间 它需要扩展。

通过简单地将shrinkWrap设置为true,将确保它包装由内容定义的大小。示例代码说明:

// ...
  ListView(
    // Says to the `ListView` that it must wrap its
    // height (if it's vertical) and width (if it's horizontal).
    shrinkWrap: true,
  ),
// ...

这就是你的代码,尽管如此,@Rémi建议是最好的,使用Align而不是Column。


这种情况通常发生在可滚动小部件嵌套在另一个可滚动小部件中时。

在我的情况下,我使用GridView在列和错误抛出。

GridView小部件有shrinkWrap属性/命名参数,将其设置为真,我的问题已经解决。

GridView.count(
  shrinkWrap: true,
  // rest of code
)

虽然shrinkWrap可以做到,但你不能在ListView中滚动。

如果你想要滚动功能,你可以添加物理属性:

ListView.builder(
    scrollDirection: Axis.vertical,
    shrinkWrap: true,
    physics: ScrollPhysics(),
...

测试第二个列表视图

ListView.builder(
            physics: NeverScrollableScrollPhysics(),

    Container(
       height: 100,
       child: ListView.builder(
       scrollDirection: Axis.vertical,
       physics: BouncingScrollPhysics(),
       shrinkWrap: true,
       itemCount: 5,
       itemBuilder: (context, index) {
       return Text("Hello World $index");
      },
    ),
  );

我想发布另一个答案,因为许多答案(包括已接受的答案!)建议在ListView.builder中使用shrinkWrap: true。虽然这消除了错误,但在这种情况下,由于性能原因,这种解决方案并不理想。Flutter设计了无限大小的ListView,专门在必要时阻止这种行为!

收缩包装滚动视图的内容比展开到允许的最大大小要昂贵得多,因为内容可以在滚动期间展开和收缩,这意味着每当滚动位置发生变化时,都需要重新计算滚动视图的大小。

在某些情况下/设备,这个属性导致故障滚动和动画滞后在我的项目。即使延迟不明显,这个属性也会影响滚动性能。

OP显示他正在为ListView创建一个小(有限)数量的子节点。如果我们想要解决这些列表的错误,谷歌建议使用一个Flexible小部件,即在列表本身上使用Expanded(带有flex 1的Flexible)。

Expanded(
    child: ListView(
        ...
    ),
) 

这里还有其他布局问题,但垂直视口无界高度是因为ListView没有一个限制其大小的父类。


如果你在2021年仍然面临这个问题…这里是最好的和简单的解决方案

      ListView.builder(
         scrollDirection: Axis.vertical,
         shrinkWrap: true,
     //     itemExtent: 400, use this if you give hight of your items
        physics: ScrollPhysics(),)

有很多解决办法。但是他们有问题…就像我们使用ListView并使用它的属性shrinkWrap .然后你会注意到滚动在ListView上不起作用所以你必须使用物理:ScrollPhysics()


我们可以用两种方法来解决上述问题

1. 使用灵活的部件,

Flexible小部件可以在Row、Column和Flex中使用。扩展以填充主轴中的可用空间的灵活性(例如,水平扩展[Row]或垂直扩展[Column])

但是,请记住,与Expanded不同,The Flexible小部件不需要子部件填充可用空间。所以,最好使用Flexible。

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

2. 使用shrinkWrap: true

使用shrinkWrap为true,我们告诉Listview渲染它的List到可用空间,而不是在剩余屏幕以下。

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

此外,物理属性可以用来允许/禁止滚动Listview

停止滚动

 ListView(
      shrinkWrap: true, 
      physics: NeverScrollableScrollPhysics(),
    ),

允许滚动

 ListView(
      shrinkWrap: true, 
      physics: ScrollPhysics(),
    ),

 

有很多答案,但每一个都有自己的局限性。每个人都在说使用shrinkWrap:没错。是的,你应该使用它,但这些代码的效果是,当你滚动列表时,它会自动移动到顶部项目,这意味着滚动回顶部。 所以完美的解决方案是使用物理收缩包装,只有列表才能顺利滚动。

      shrinkWrap: true,          //
      physics: ScrollPhysics(),  // both line is mandatory

如果你想看Listview的其他例子。生成器与列作为子和列表可以垂直滚动,然后你可以看到这里的例子-在垂直列表中排列多个文本。


只是想添加我的解决方案,在我的情况下,我有垂直列表视图与其他按钮和文本在同一屏幕上:

Flexible(
child:  
  ListView.builder(
  // make sure to add the following lines:  
  shrinkWrap: true,
  physics: ScrollPhysics(),
  // the rest of your list view code
 ) // ListView
) // Flexible

这个解决方案工作得很好,特别是当您在同一屏幕上有其他小部件时。在这种特殊情况下,仅使用“Expand”或“Flexible”是行不通的。


也会遇到这种错误,因为代码是这样的

return Container(
      child: Column(
        children: [
          ListView.separated(
              itemBuilder: (context, index) {
                return CircleManagerSettingItem(widget.membersInfo[index]);
              },
              separatorBuilder: (_, index) => DD(
                    height: 1,
                    paddingLeft: 10,
                    paddingRight: 10,
                  ),
              itemCount: (widget.membersInfo.length)),
        ],
      ),
    );

删除容器内的列,然后确定。


在我的情况下,我必须包装ListView在一个容器内,并给这个容器一个特定的高度


Viewport异常的原因

GridView / ListView增长,直到约束(限制)停止这种扩展,然后滚动查看超出该大小的项目。

但是Column没有任何约束地布局它的子节点,完全忽略了它自己的大小和屏幕大小。柱内空间无限。

由于Grid/ListView在列内扩展到无穷大,导致Viewport被给予无界高度异常。

灵活/扩展的存在给列的子约束基于列的大小。(除了在Row和Column中,这两个小部件不能在其他任何地方使用。)

在Column中的Flexible/Expanded小部件中,Grid/ListView只使用未被其他非Flexible小部件占用的剩余空间,这些小部件首先被布局。(布局阶段信息见底部。)

shrinkWrap不是一个好的解决方案

在列的ListView中使用shrinkWrap: true并没有真正的帮助,因为:

ListView不再滚动 ListView仍然会溢出

一个足够高的ListView来显示它所有的项,不会滚动。可以说,这违背了使用ScrollView小部件(ListView的父类)的目的。

在列布局阶段1(见底部布局阶段的解释),ListView可以是任何它想要的高度(没有限制)。 带有shrinkWrap:true的ListView将增加高度以显示其所有项。 有了足够多的项目,一个收缩包装的ListView将增长&增长(它从不滚动)溢出任何列在里面,无论是屏幕或其他更严格的约束。

难道shrinkWrap不应该只是让ListView只和它的项目或剩余空间一样大(直到屏幕高度),然后滚动吗?

这在直觉上是有意义的,但是在第一阶段的Column布局中是在无界空间中完成的。

所以剩余空间是无限的。没有达到最大高度。true只会随着项目的增加而不断增加列的高度,直到满屏(或其他较小的约束)。

使用实例shrinkWrap:true溢出

下面是一个例子,将项目添加到一个列的收缩包装的ListView中,直到它的高度高于屏幕,创建一个溢出警告区域:

(只要一直按+号浮动动作按钮)

import 'package:flutter/material.dart';

class ColumnListViewPage extends StatefulWidget {
  @override
  _ColumnListViewPageState createState() => _ColumnListViewPageState();
}

class _ColumnListViewPageState extends State<ColumnListViewPage> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Column & ListView'),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          setState(() {
            _count++;
          });
        },
      ),
      body: SafeArea(
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(color: Colors.red)
          ),
          /// // without center, Column will be as narrow as possible
          alignment: Alignment.center,
          /// Column is forced (constrained) to match screen dimension,
          child: Column(
            children: [
              Text('Inner (Nested) Column'),
              ListView.separated( // ← should be wrapped in Expanded
                itemCount: _count,
                separatorBuilder: (context, index) => const Divider(),
                itemBuilder: (context, index) => Padding(
                  padding: const EdgeInsets.symmetric(vertical: 38.0),
                  child: Text('Row $index'),
                ),
                shrinkWrap: true, // should be removed
              )
            ],
          ),
        ),
      ),
    );
  }
}

对于列中的GridView/ListView,在Expanded或Flexible中包装可能是最安全的解决方案。


扩展/灵活

Expanded和Flexible只能在Column(以及它的兄弟姐妹Row等)中使用。

它们必须作为Column的直接子节点使用。我们不能在SizedBox或其他小部件中“嵌套”Expanded/Flexible。仅直接在列下作为直系子女。

在Column中,将ListView/GridView放置在Expanded或Flexible中可以确保它只使用可用空间,而不是无限空间。

Column
→ Expanded
  → ListView

列中的Expanded/Flexible中的ListView/GridView不需要shrinkWrap,因为它是受限的(给定一个max。通过Expanded/Flexible小部件。因此,当约束/定义高度用完时,ListView/GridView将停止增长并开始滚动。


栏目布局阶段

列将子元素分为两个阶段:

第一无约束(无界空间) 第二,剩余空间基于列的父节点

第一阶段

任何不在Flexible或Expanded中的Column子元素都将在阶段1中被布局,在无限的空间中,完全忽略屏幕大小。

需要垂直边界/约束来限制其增长的小部件(例如ListView)将在阶段1中导致vertical viewport被给予无界高度异常,因为在无界空间中没有垂直边界。

大多数小部件都有固有大小。以文本为例,它的高度取决于它的内容和字体大小/样式。它不会为了填满空间而生长。定义高度的小部件在列布局的第一阶段表现良好。

第二阶段

任何增长到填充边界的小部件,都应该放在阶段2的Flexible或Expanded布局中。

阶段2计算Column的父约束减去阶段1中使用的空间的剩余空间。剩余的空间作为约束提供给阶段2的子节点。

例如,ListView只会增长到使用剩余空间并停止,避免视口异常。

更多关于列布局算法和如何扩展工作在它。


我做了一个自定义函数来解决你的问题。 你可以直接在你的代码库中使用这个函数:

Widget horizontalListView(height, width, color, child, margin) {
return Column(
  children: [
    SizedBox(
      height: 200,
      child: ListView.builder(
        itemCount: 10,
        shrinkWrap: true,
        scrollDirection: Axis.horizontal,
        itemBuilder: (context,index) {
          return Container(
            height: height,
            width: width,
            margin: EdgeInsets.all(margin),
            color: color,
            child: child
          );
        }
      ),
    ),
  ],
 );
})

附注:对不起,代码对齐不好。


如果你使用CustomScrollView

你可以试试SliverFillRemaining


我面临这个问题,因为我想在一个ListView中显示一个GridView,解决方案是通过添加以下内容,不仅在ListView中,而且在GridView中:

收缩包装:真 scrollDirection: Axis.vertical


ListView.builder(
                scrollDirection: Axis.vertical,
                shrinkWrap: true,
                itemCount: 10,
                itemBuilder: (BuildContext context, int index) {
                  return Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Container(
                      height: 100,
                      width: double.infinity,
                      color: Colors.pinkAccent,

                    ),
                  );
                },
              ),

加上这两行

ListView.builder ( scrollDirection: Axis.vertical, 收缩包装:没错,

...


您也可以将Expanded()作为该小部件的父部件。