【问题标题】:Flutter ListView.Builder() in scrollable Column with other widgetsFlutter ListView.Builder() 在可滚动列中与其他小部件
【发布时间】:2018-11-20 11:38:35
【问题描述】:

我有一个带有大量不同视图的 TabBarView()。我希望它们成为顶部有 TextField 和下方有 ListView.Builder() 的 Column,但两个小部件应位于同一可滚动区域(scrollview)中。我实现它的方式引发了一些错误:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder)
    ],
   );
}

错误:

I/flutter (23520): The following assertion was thrown during performResize():
I/flutter (23520): Vertical viewport was given unbounded height.
I/flutter (23520): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter (23520): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter (23520): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter (23520): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter (23520): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter (23520): instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size
I/flutter (23520): the height of the viewport to the sum of the heights of its children.

我阅读了有关在扩展区域中堆叠 ListView.builder() 的信息,但它使文本字段有点“粘性”,这不是我想要的。 :-)

我也遇到过 CustomScrollView,但不完全了解如何实现它。

【问题讨论】:

  • 用展开的小部件包装 ListView

标签: flutter dart flutter-layout


【解决方案1】:

解决办法如下:

SingleChildScrollView(
        physics: ScrollPhysics(),
        child: Column(
          children: <Widget>[
             Text('Hey'),
             ListView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                itemCount:18,
                itemBuilder: (context,index){
                  return  Text('Some text');
                })
          ],
        ),
      ),

【讨论】:

  • 它对我来说并不完全有效,我需要为 columnMainAxisSize.min 添加属性才能使其工作。
  • @PedroMolina 您是否在您的ListView 中添加了shrinkWrap: true,因为没有它也可以工作。不过感谢@SunpreetSingh
  • “物理:NeverScrollableScrollPhysics()”救了我。谢谢!
  • 非常感谢兄弟
  • 你拯救了我的一天。我一直想知道为什么 NeverScrollableScrollPhysics() 甚至存在。现在我知道为什么了:D
【解决方案2】:

将 ListView 放在 Expanded 小部件中应该可以解决您的问题:

@override
Widget build(BuildContext context) {
return new Column(
  mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      new Padding(
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: new TextField(
            decoration: new InputDecoration(
                hintText: "Type in here!"
            ),
          )
      ),
      new Expanded(child: ListView.builder(
          itemCount: _posts.length, itemBuilder: _postBuilder))
    ],
   );
}

【讨论】:

  • 据我了解,Expanded 和 ListView 一起工作,因为expanded 使用了屏幕的其余部分。因此,如果您想要展开下方的按钮,您首先需要填充的文本字段,然后展开(可滚动),然后是屏幕底部的按钮。
  • 如果此解决方案有问题,请验证该列是否在定位内。如果是这样,您需要指定顶部和底部。所以飞镖可以计算大小。仅指定 top 将导致计算数据不足。
  • 这是正确的方法,应该是公认的答案,因为它满足了我们不希望整个页面滚动但只滚动列表视图的用例。
【解决方案3】:

使用SingleChildScrollView 允许子小部件滚动

解决方案

SingleChildScrollView(
          child: Column(
            children: <Widget>[
                      ListView.builder(
                      shrinkWrap: true,
                      physics: NeverScrollableScrollPhysics(),

这里使用了两个属性

shrinkWrap: true

只占用它需要的空间(当有更多项目时它仍然会滚动)。

physics: NeverScrollableScrollPhysics()

不允许用户滚动的滚动物理。意味着只有 Column+SingleChildScrollView 滚动工作。

【讨论】:

  • 此解决方案效率低下,因为列表视图将立即构建所有项目,从而消除了性能优势。
  • @kemist:那么理想的解决方案是什么?
  • @jitsm555 您想使用带有 SliverList 和 SliverChildBuilderDelegate 的 CustomScrollView。
  • @jitsm555 检查我的解决方案:stackoverflow.com/a/65340391/9695723
  • 但是这个解决方案 NotificationListener 不起作用
【解决方案4】:

错误原因:

Column 扩展到主轴方向(垂直轴)的最大尺寸,ListView 也是如此

解决方案

您需要限制ListView 的高度,使其扩展以匹配Column,解决此问题有多种方法,我在这里列出一些:


  1. 如果您想让ListView 占用Column 内的所有剩余空间,请使用Flexible

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

  1. 如果您想将您的ListView 限制为某个height,您可以使用SizedBox

    Column(
      children: <Widget>[
        SizedBox(
          height: 200, // constrain height
          child: ListView(),
        )
      ],
    )
    

  1. 如果你的ListView 很小,你可以试试shrinkWrap 属性。

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

【讨论】:

  • 3 号解决了我的问题。谢谢,很好的答案!
  • 我收到Incorrect use of ParentDataWidget. 方法1
  • @PiyushChauhan 你可能错过了包含Column。如果不是这种情况,请提出一个单独的问题,我很乐意为您提供帮助。
  • 我的 Listview 周围没有灵活的小部件——只有一个 Expanded 小部件围绕它是其后代的 Column 部分。这对我很有帮助,谢谢!
【解决方案5】:

ListView.Builder() 中使用 physics: NeverScrollableScrollPhysics()shrinkWrap: true 并享受

【讨论】:

    【解决方案6】:

    使用 Expanded 小部件来约束而不溢出这些像素,:)

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

    【讨论】:

      【解决方案7】:

      添加

      Column(
      mainAxisSize: MainAxisSize.max, //Add this line onyour column
      children:[
          SomeWidget(),
          Expanded(child:ListView.builder())
        ]
      )
      

      【讨论】:

        【解决方案8】:

        就我的未来而言,我是这样做的:

        SingleChildScrollView(
              physics: ScrollPhysics(),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Text("Hey ho let's go!"),
                  
                  Flexible(
                    child: FutureBuilder(
                      future: getData(),
                      builder: (BuildContext context,
                          AsyncSnapshot<List<Sale>> snapshot) {
                        
        
                        if (snapshot.connectionState != ConnectionState.done ||
                            snapshot.hasData == null) {
                          
                            return CircularProgressIndicator();
        
                        } else {
                          data = snapshot.data;
                          return ListView.builder(
                              physics: NeverScrollableScrollPhysics(),
                              shrinkWrap: true,
                              itemBuilder: (BuildContext context, int index) {
                                return dataItemWidget(size, data[index], context);
                              },
                              itemCount: data.length,
                            );
                        }
                      },
                    ),
                  ),
                ],
              ),
            ),
        

        【讨论】:

          【解决方案9】:
          //If you want Listview.builder inside ListView and want to scroll the parent ListView// //whenever the Items in ListView.builder ends or start you can do it like this
                 body: ListView(
                            physics: ScrollPhysics(),
                            children: [
                              SizedBox(height: 20),
                              Container( height: 110.0 *5, // *5 to give size to the container //according to items in the ListView.builder. Otherwise will give hasSize Error
                              child:ListView.builder(
                                 physics: NeverScrollableScrollPhysics(),
                                 scrollDirection: Axis.vertical,
                                 itemCount: 5,
                                  itemBuilder: (BuildContext context, int indexChild) {
                                   return InkWell(child:Container(height:100));}))                
                              ),]),
          

          【讨论】:

            【解决方案10】:

            这是一个有效的解决方案:

            class NestedListExample extends StatelessWidget {
              @override
              Widget build(BuildContext context) {
                return CustomScrollView(
                  slivers: [
                    const SliverToBoxAdapter(
                      child: Text('Header'),
                    ),
                    SliverList(
                      delegate: SliverChildBuilderDelegate(
                        (ctx, index) {
                          return ListTile(title:Text('Item $index'));
                        },
                      ),
                    ),
                  ],
                );
              }
            }
            

            这是 dartpad 上的 preview

            您可以为其他孩子使用 SliverToBoxAdapter,因为只有 Sliver 可以是 CustomScrollView 的直接孩子。

            如果所有列表项的高度相同,那么您可以使用SliverFixedExtentList,这样更有效,因为每个子项的高度不是即时计算的,但您必须知道确切的像素高度。您还可以使用SliverPrototypeExtentList,在其中提供列表中的第一项(原型),所有其他子项将使用原型的高度,因此您无需知道以像素为单位的确切高度。

            【讨论】:

            • 这绝对是任何体面列表的最佳解决方案
            【解决方案11】:

            只需在 ListView.builder() 中添加 physics: NeverScrollableScrollPhysics() 即可滚动

            【讨论】:

            • 请在答案中包含更多上下文
            【解决方案12】:

            Listview.builder()方法中添加physics: NeverScrollableScrollPhysics(),嵌套的Listview会滚动

            【讨论】:

              【解决方案13】:

              Column 不可滚动,这就是为什么顶部的 TextField 不会滚动,而底部的 ListView 会滚动。

              我认为解决此问题的最佳方法是将您的TextField 设为ListView 中的第一项。

              因此您不需要列,您的父小部件是 ListView,其子小部件是 TextField,然后是您使用 _postBuilder 构建的其余项目。

              【讨论】:

                【解决方案14】:

                最好的方法是使列可滚动,方法是使列成为 SingleChildScrollView 的子列,然后将相同的 ScrollController 分配给 SingleChildScrollView 和 ListView.builder。这将使文本字段和下面的 ListView 成为可滚动的。

                【讨论】:

                  【解决方案15】:
                  return Column(
                           children: [
                             Text("Popular Category"),
                              Expanded(
                           child: ListView.builder(`enter code here`
                               shrinkWrap: false,
                               scrollDirection: Axis.horizontal,
                               itemCount: 3,
                               itemBuilder: (context, index) {
                                 return Row(
                                   crossAxisAlignment: CrossAxisAlignment.start,
                                   children: [
                                     Text("hello"),
                                   ],
                                 );
                               }),   
                             ),
                           ],    
                       );
                  

                  【讨论】:

                    猜你喜欢
                    • 2021-07-30
                    • 2021-11-04
                    • 2021-08-12
                    • 2019-11-30
                    • 1970-01-01
                    • 2021-06-16
                    • 2020-11-05
                    • 2019-01-31
                    • 1970-01-01
                    相关资源
                    最近更新 更多