223

这是我的代码:

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

20 回答 20

492

添加这两行

ListView.builder(
    scrollDirection: Axis.vertical,
    shrinkWrap: true,
...
于 2019-02-08T07:08:33.590 回答
231

当您尝试在a中使用ListView/时,通常会发生这种情况,有很多解决方法,我在这里列出一些。GridViewColumn

  1. 包裹ListView起来Expanded

    Column(
      children: <Widget>[
        Expanded( // wrap in Expanded
          child: ListView(...),
        ),
      ],
    )
    
  2. 包裹ListViewSizedBox给出一个有界的height

    Column(
      children: <Widget>[
        SizedBox(
          height: 400, // fixed height
          child: ListView(...),
        ),
      ],
    )
    
  3. shrinkWrap: true中使用ListView

    Column(
      children: <Widget>[
        ListView(
          shrinkWrap: true, // use this
        ),
      ],
    )
    
于 2019-08-03T03:18:35.947 回答
46

因此,每个人都发布了答案,但没有人愿意解释原因:我将复制有关以下内容的文档shrinkWrap

[scrollDirection] 中滚动视图的范围是否应由正在查看的内容决定。

如果滚动视图不收缩包裹,那么滚动视图将展开到 [scrollDirection] 中允许的最大尺寸。如果滚动视图在 [scrollDirection] 中有无限约束,则 [shrinkWrap] 必须为真。

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

默认为false.

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

...垂直视口被赋予了无限量的垂直空间来扩展。

通过简单地设置shrinkWraptrue确保它包含由内容定义的大小。一个示例代码来说明:

// ...
  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.

于 2019-10-28T15:50:51.297 回答
31

将网格视图放在灵活或扩展小部件中

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(),
          );
        }),))]
    )
);
于 2018-09-04T18:27:43.760 回答
18

虽然shrinkWrap做的事情,但你不能滚动ListView

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

ListView.builder(
    scrollDirection: Axis.vertical,
    shrinkWrap: true,
    physics: ScrollPhysics(),
...
于 2020-05-15T13:42:15.100 回答
17

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

在我的情况下,我在 Column 内部使用 GridView 并且抛出该错误。

GridView 小部件具有shrinkWrap属性/命名参数,设置它true我的问题是固定的。

GridView.count(
  shrinkWrap: true,
  // rest of code
)
于 2020-02-14T16:32:15.317 回答
12

这个答案基于@CopsOnRoad 的北部

发生这种情况是因为ListView/GridView小部件没有父级来获取它的大小,所以它的高度是无限的,并且颤动不知道 ListView 的高度并且无法渲染。

  1. 解决方案一:固定高度

    Container直接用or把它包起来SizedBox写死高度。

    Column(
      children: <Widget>[
        SizedBox(
         height: 400, // fixed height
        child: ListView(...),
       ),
     ],
    )
    

这很好,但是如果高度需要自适应,你写它就行不通了。

  1. 解决方案二:shrinkWrap: true

    尝试滚动shrinkWrap: true_physics: ScrollPhysics()

    shrinkWrap: true有点像在android的wrap_content.

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

但是,编译后,您会在页面底部发现一个长长的黄色警告。

所以还是不能

  1. 解决方案三:扩展或灵活

    Flexible是flutter中的灵活布局,相当于android中的LinearLayout。

    Flexible中有一个flex属性,等于layout_weight,占用了所有剩余空间。

    所以,我们可以用 Flexible 包装 ListView。

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

这个答案基于:垂直视口被赋予了无限的高度。

于 2020-09-17T06:31:34.087 回答
10

不要Column用于单子对齐。改为使用Align

    new Align(
      alignment: Alignment.topCenter,
      child: new GridView(),
    )
于 2018-05-09T11:48:01.687 回答
8

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

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

如果您想查看 Listview.builder 的其他示例,其中列作为子项并且列表可以垂直滚动,那么您可以在此处查看示例- 在垂直列表中排列多个文本。

于 2021-06-23T07:18:57.423 回答
8

视口异常的原因

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

但是没有任何约束Column地布置它的孩子,完全忽略了它自己的尺寸和屏幕尺寸。里面有无限的空间。Column

Viewport was given unbounded height发生异常是因为Grid/ListView在 a 内扩展到无穷大Column

Flexible/Expanded存在给孩子们基于大小Column的约束。Column's(这两个小部件不能在其他任何地方使用,除了 insideRowColumn。)

在 中的Flexible/Expanded小部件内部ColumnGrid/ListView仅使用其他非灵活小部件未占用的剩余空间,这些小部件首先布局。(有关布局阶段信息,请参见底部。)

shrinkWrap不是一个好的解决方案

在a 内使用shrinkWrap: trueon并没有真正的帮助,因为:ListViewColumn

  • ListView不再滚动
  • ListView仍然可以溢出

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

Column布局阶段 1(请参阅底部以了解布局阶段的说明),ListView可以是它想要的任何高度(没有约束)。一个ListViewwithshrinkWrap:true将增加高度以显示其所有项目。有了足够的项目,ashrinkWrapped ListView将会增长和增长(它永远不会滚动)以溢出Column内部的任何内容,无论是屏幕还是其他更严格的约束。

不应该shrinkWrap只制作与其项目ListView剩余空间一样大(直到屏幕高度),然后滚动?

这很直观,但Column在第一阶段的布局中是在无界空间中完成的。

因此,剩余空间是无限/无限的。永远不会达到最大高度。shrinkWrap:true随着项目的添加,高度只会保持增长Column,直到溢出屏幕(或其他较小的约束)。

示例shrinkWrap:true溢出

这是一个将项目添加到收缩包装的示例,ListView直到Column其高度高于屏幕,从而创建溢出警告区域:

(只需按住+号浮动操作按钮)

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/ListViewin a Column,包裹在ExpandedorFlexible可能是最安全的解决方案。

扩展/灵活

Expanded并且Flexible只能在内部使用Column(及其兄弟姐妹,如Row等)。

它们必须用作 的直接子级Column。我们不能“嵌套” Expanded/ FlexibleinSizedBox或其他小部件。仅直属Column直属子级。

在内部Column,放置或确保它将仅使用可用空间,而不是无限空间。ListView/GridViewExpandedFlexible

Column
→ Expanded
  → ListView

ListView/GridViewinside Expanded/Flexiblein aColumn不需要shrinkWrap,因为它受小部件的限制(给定最大高度)Expanded/Flexible。因此,当该约束/定义的高度用完时,ListView/GridView将停止增长并开始滚动。


列布局阶段

Column分两个阶段布置孩子:

  • 第一个没有约束(无限空间)
  • 第二个基于Column's父级的剩余空间

阶段1

任何不在里面的Column孩子或将在第 1 阶段被布置在无限、无限的空间中,完全忽略屏幕尺寸FlexibleExpanded

需要垂直边界/约束来限制其增长(例如ListView)的小部件将在阶段 1 中导致Vertical viewport was given unbounded height异常,因为在无界空间中没有垂直边界

大多数小部件都有固有尺寸。 Text例如,仅与其内容和字体大小/样式一样高。它不会试图增长来填充空间。Column定义高度的小部件在布局的第一阶段表现良好。

阶段2

任何增长到填充边界的小部件都应放入FlexibleExpanded用于阶段 2 布局。

Column's第 2 阶段从其父约束减去第 1 阶段使用的空间计算剩余空间。该剩余空间作为约束提供给第 2 阶段子约束。

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

Column有关布局算法的更多信息以及其中的Expanded工作原理

于 2021-12-14T19:44:21.927 回答
3

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

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

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

OP表明他正在为ListView. 如果我们想解决这些列表的错误,Google建议在列表本身上使用一个Flexible小部件,即Expanded(a Flexiblewith flex 1)。

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

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

于 2021-05-02T20:17:04.223 回答
3

如果您在 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()

于 2021-06-09T06:34:44.013 回答
2
    Container(
       height: 100,
       child: ListView.builder(
       scrollDirection: Axis.vertical,
       physics: BouncingScrollPhysics(),
       shrinkWrap: true,
       itemCount: 5,
       itemBuilder: (context, index) {
       return Text("Hello World $index");
      },
    ),
  );
于 2021-03-13T12:34:14.223 回答
2

解决上述问题的两种方法

1.使用灵活的小部件,

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

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

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

2.使用shrinkWrap:true

使用shrinkWrap为真,我们告诉 Listview 将其列表呈现到可用空间,而不是低于剩余屏幕。

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

此外,physics属性可用于允许/禁止滚动Listview

停止滚动

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

允许滚动

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

 
于 2021-06-12T12:57:06.707 回答
1

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

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

当您在同一屏幕上有其他小部件时,此解决方案尤其适用。在这种特殊情况下,单独使用“扩展”或“灵活”是行不通的。

于 2021-10-09T20:40:47.643 回答
1

测试这个第二个列表视图

ListView.builder(
            physics: NeverScrollableScrollPhysics(),
于 2020-07-11T08:49:01.237 回答
0

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

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

PS抱歉代码对齐错误。

于 2022-02-11T04:40:58.143 回答
0

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

于 2021-11-29T20:08:11.023 回答
0

也遇到这个错误,因为这样的代码

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

去掉Column里面Container然后就OK了。

于 2021-10-13T10:00:54.287 回答
-1

有一个名为 Center 的小部件。它应该可以帮助您实现您想要做的事情(垂直居中)。Center 小部件的官方文档

于 2019-10-11T16:58:12.403 回答