这是我的代码:

@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)

当前回答

所以,每个人都上传了答案,但没有人愿意解释原因: 我将复制关于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。

其他回答

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

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

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

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

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

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

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只会增长到使用剩余空间并停止,避免视口异常。

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

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

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

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

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