给定的垂直视口高度未被限定

334

这是我的代码:

@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(主要用于多个子小部件)。 - Napolean
1
小部件构建(BuildContext context) { 返回新的材料( 颜色:Colors.deepPurpleAccent, 孩子:新容器( 对齐方式: 对齐.中心, 孩子: 新网格视图计数(crossAxisCount:_column,children:新列表生成(_row*_column, (索引) { 返回新中心( 孩子: 新单元小部件() ); }) ), ) ); --此代码也不能帮助@Napolean - pallav bohara
尝试在Column下添加mainAxisSize到max,并查看是否有所帮助。 - pblead26
27个回答

6
我想再发一篇回答,因为很多回答(包括被采纳的回答!)建议在ListView.builder中使用shrinkWrap: true。虽然这可以解决错误,但是对于这种情况,这种解决方案出于性能原因不是理想的!Flutter专门为具有无限大小的ListView设计,仅在必要时才会阻止此行为!

收缩滚动视图内容的成本显着高于扩展到最大允许大小,因为内容在滚动期间可能会扩展和收缩,这意味着每当滚动位置更改时都需要重新计算滚动视图的大小。

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

这篇文章显示作者正在为 ListView 创建一个有限数量的子项。如果我们想要解决这些列表的错误,Google 建议 在列表本身上使用 Flexible 小部件,即使用 Expanded(带有 flex 1 的 Flexible)。

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

这里存在其他布局问题,但是垂直视口无界高度是由于ListView没有父级来限制其大小。

虽然这是真实的,但有很多用例中ListView需要合理地与父级组件Semantics(参见image_picker示例)一起使用,而shrinkWrap在这些情况下扮演了重要角色。感谢这很有帮助,让我更好地理解了权衡之处。您可能想要添加ScrollPhysics来测试性能影响。Expanded需要嵌套在一个Flexible Widget的直接子节点中,这有时会限制它的使用。 - Tommie C.

4

我们可以通过两种方式解决上述问题:

1. 使用Flexible Widget

Flexible Widget 可以用于 Row、Column 和 Flex 中。它具有在主轴(例如,[Row] 的水平方向或 [Column] 的垂直方向)中扩展以填充可用空间的灵活性。

但请记住,与 Expanded 不同,Flexible Widget 不要求子 Widget 填充可用空间。因此,最好始终使用 Flexible

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

2. 使用 shrinkWrap: true

当我们将 shrinkWrap 设置为 true 时,我们告诉 ListView 在可用空间内呈现其列表,而不是占据剩余屏幕以下的空间。

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

此外,physics 属性可用于允许/禁止 Listview 的滚动。
停止滚动。
 ListView(
      shrinkWrap: true, 
      physics: NeverScrollableScrollPhysics(),
    ),

允许滚动

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

 

4
我面临的问题是想在ListView中显示一个GridView。解决方法是不仅在ListView中添加以下内容,在GridView中也要添加:
  1. shrinkwrap: true
  2. scrollDirection: Axis.vertical

欢迎来到SO。虽然我们感谢您的回答,但如果它能在其他答案的基础上提供额外的价值,那就更好了。在这种情况下,您的答案并没有提供额外的价值,因为另一个用户已经发布了该解决方案。如果以前的答案对您有帮助,您应该在获得足够的声望后投票支持它。 - lepsch
1
我明白了,但是所有添加这些步骤的答案都只是在列表视图中,我已经尝试过了,错误仍然没有改变。在不仅仅是列表视图中添加这些步骤,而且在网格视图中添加后,它就可以工作了。我只是说一下我的经历。 - Marim mohamed
明白了。我会编辑答案,让它更加清晰。比如说:“我遇到这个问题是因为我想在 ListView 中显示一个 GridView,解决方法是不仅要在 ListView 中添加以下内容,还要在 GridView 中添加以下内容:”。 - lepsch
这正是我想通过我的回答澄清的内容,感谢您的理解。 - Marim mohamed

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

                    ),
                  );
                },
              ),

1
你好,欢迎来到Stackoverflow。shrinkWrap: true已经在顶层得到了回答,尽可能避免使用它。 - Yeasin Sheikh

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 上的滚动不起作用,因此必须使用 physics: ScrollPhysics()。

3

终于解决了!

我遇到了一个问题,即在列中有2个嵌套的Listview.builders。 布局动态计算,您无法为ListView.builder设置固定高度(例如通过SizedBox)。

为了避免这个问题,请尝试:

  1. 将您的Column更改为widget ListView
  2. 然后确保您使用 Expanded widget包装它以利用所有可用空间。 (或者尝试使用Padding,有时也可以工作,但我不明白为什么)。
  3. 然后将 shrinkWrap 属性设置为 true 以限制其大小。在 Listvie.builder 内部,也要将 shrinkWrap 设置为 true 以限制其大小。在这里,您还必须添加 physics:ScrollPhysics()使其可滚动。

这里是一个简单的示例,但当然适用于更复杂的结构。

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Column(
            children: [
              Expanded(
                child: ListView(
                  shrinkWrap: true,
                  children: [
                    ListView.builder(
                        shrinkWrap: true,
                        physics: ScrollPhysics(),
                        itemCount: 100,
                        itemBuilder: (context, i) {
                          return Center(
                            child: Text('index is $i'),
                          );
                        })
                  ],
                ),
              ),
              Container(
                height: 400,
                decoration: BoxDecoration(color: Colors.greenAccent),
              )
            ],
          ),
        ),
      ),
    );
  }
}

这里也有一个嵌套的ListView.builder示例:

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Column(
            children: [
              Expanded(
                child: ListView(
                  shrinkWrap: true,
                  children: [
                    ListView.builder(
                        shrinkWrap: true,
                        physics: ScrollPhysics(),
                        itemCount: 100,
                        itemBuilder: (context, i) {
                          return Column(
                            children: [
                              Center(
                                child: Text(
                                  'index is $i',
                                  style: TextStyle(fontSize: 24),
                                ),
                              ),
                              ListView.builder(
                                  shrinkWrap: true,
                                  itemCount: 4,
                                  physics: NeverScrollableScrollPhysics(),
                                  itemBuilder: (context, j) {
                                    return Center(
                                      child:
                                          Text('nested ListView index is: $j'),
                                    );
                                  }),
                              Divider(
                                height: 1,
                                thickness: 2,
                                color: Colors.blueGrey,
                              )
                            ],
                          );
                        }),
                  ],
                ),
              ),
              Container(
                height: 400,
                decoration: BoxDecoration(color: Colors.greenAccent),
              )
            ],
          ),
        ),
      ),
    );
  }
}

1
这个按预期工作 - Kheersagar patel

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

1
如果滚动视图在滚动方向上具有无限制的约束,则shrinkWrap必须为true。 - user15388500

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

这种解决方案特别适用于屏幕上有其他小部件的情况。在这种特殊情况下,仅使用“Expand”或“Flexible”是不起作用的。

1

测试第二个列表视图

ListView.builder(
            physics: NeverScrollableScrollPhysics(),

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

附言:对于代码的不良对齐表示抱歉。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接