Flutter ListView.Builder() 在可滚动列中与其他小部件

Posted

技术标签:

【中文标题】Flutter ListView.Builder() 在可滚动列中与其他小部件【英文标题】:Flutter ListView.Builder() in scrollable Column with other widgets 【发布时间】: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 【参考方案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 检查我的解决方案:***.com/a/65340391/9695723 但是这个解决方案 NotificationListener 不起作用【参考方案4】:

错误原因:

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

解决方案

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


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

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

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

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

    如果你的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"),
                 ],
               );
             ),   
           ),
         ],    
     );

【讨论】:

以上是关于Flutter ListView.Builder() 在可滚动列中与其他小部件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 中添加 ListView.builder 的填充顶部?

Flutter - ListView.builder:初始滚动位置

Flutter:ListView.builder 创建列

Flutter - 另一个 Listview 中的 Listview.builder

Flutter:ListView.builder 中的自动垂直高度

Flutter 应用程序,ListView.builder 首次运行时出现错误。需要重启应用(ListView.builder 和 image_picker)