这是我的代码:

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

当前回答

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

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

其他回答

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

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

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

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

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

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

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

将网格视图放置在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(),
          );
        }),))]
    )
);