垂直视口高度为无界

这是我的代码:

@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)
231249 次浏览

不要使用Column进行单子对齐。请改用Align

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

将网格视图放在FlexibleExpanded小部件内

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

当你试图在Column中使用ListView/GridView时,通常会发生这种情况,有很多方法来解决它,我在这里列出了一些。

  1. ListView包装在Expanded

    Column(
    children: <Widget>[
    Expanded( // wrap in Expanded
    child: ListView(...),
    ),
    ],
    )
    
  2. Wrap ListView in SizedBox and give a bounded height

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

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

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

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

[scrollDirection]中滚动视图的范围是否为

.

.

如果滚动视图没有收缩wrap,则滚动视图将展开 到[scrollDirection]中允许的最大大小。如果滚动视图 在[scrollDirection]中有无限约束,那么[shrinkWrap]必须吗 是真的。< / p >

收缩包装滚动视图的内容明显更多 比扩展到允许的最大大小更昂贵,因为内容 可以在滚动时伸缩,这意味着 当滚动位置改变时,需要重新计算滚动视图

默认为false

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

< p >…垂直视口被赋予无限的垂直空间

通过简单地将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属性/命名参数,设置它true我的问题已经解决。

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

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

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

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。虽然这样可以消除错误,但这种情况下的解决方案是NOT为性能原因的理想选择。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不同,Flexible小部件不需要子部件填充可用空间。因此,使用Flexible总是更好。

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

2. 使用shrinkWrap: true

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

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

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

停止滚动

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

允许滚动

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


 

答案有很多,但每一个都有自己的局限性。每个人都在说使用收缩包装:真。是的,你应该使用它,但这些代码的效果是,当你滚动列表时,它会自动移动到顶部项目,这意味着滚动回顶部。 所以完美的解决方案是使用收缩膜与物理,这样只有列表才能平滑地滚动
      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

这个解决方案工作得很好,特别是当您在同一屏幕上有其他小部件时。在这种特殊情况下,"扩大"或“;灵活的"光靠自己是不行的。

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

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

Container中删除Column,然后Ok。

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

Viewport异常的原因

GridView / ListView 成长直到约束 (limits)停止此扩展然后滚动查看超出该尺寸的项目。

但是Column将它的子代没有任何约束,完全忽略它本身的大小和屏幕大小Column中有无限的空间。

发生Viewport was given unbounded height异常是因为Grid/ListViewColumn中扩展到无穷大。

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

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

shrinkWrap不是一个好的解决方案

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

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

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

Column布局阶段1中(关于布局阶段的解释见底部),ListView可以是它想要的任何高度(没有限制)。 带有shrinkWrap:trueListView将增加高度以显示其所有项。 有了足够多的项,shrinkWrapped ListView将增长&无论Column是屏幕还是其他更严格的约束,

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

这在直观上是有意义的,但是在阶段1中的布局在无界空间中完成Column

所以剩余空间是无限的。没有达到最大高度。随着项目的增加,shrinkWrap:true只会继续增加Column的高度,直到满屏(或其他较小的限制)。

使用实例shrinkWrap:true溢出

下面是一个向Column中缩水包装的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
)
],
),
),
),
);
}
}
对于Column中的GridView/ListView,在ExpandedFlexible中包装可能是最安全的解决方案。

扩展/灵活

ExpandedFlexible只能在Column(以及它的兄弟姐妹,如Row等)中使用。

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

Column内部,将ListView/GridView放在ExpandedFlexible中可以确保它只使用可用空间,而不是无限空间。

Column
→ Expanded
→ ListView

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


栏目布局阶段

Column分2个阶段布局子:

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

第一阶段

FlexibleExpanded中的任何Column将在阶段1中,在无限、无限的空间完全忽略屏幕大小中布局。

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

大多数小部件都有固有大小。例如,Text只与它的content &字体大小/风格。它不会为了填满空间而生长。定义高度的小部件在Column布局的阶段1中表现良好。

第二阶段

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

阶段2根据阶段1中使用的父约束<强> - < / >强空间计算Column's剩余空间。剩余的空间作为约束提供给阶段2的子节点。

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

更多关于__ABC0布局算法以及Expanded如何在其中工作的信息

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

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中也添加以下内容:

  1. shrinkwrap: true
  2. 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,


),
);
},
),

加上这两行

< p > ListView.builder ( scrollDirection: Axis.vertical, 收缩包装:真的,< / p >

...