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

问题描述 投票:0回答:18

我有一个带有大量不同视图的 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 但没有完全理解如何实现它。

flutter dart flutter-layout
18个回答
278
投票

解决方案如下:

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

146
投票

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

69
投票

使用

SingleChildScrollView
允许子部件滚动

解决方案

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

这里使用了两个属性

shrinkWrap: true

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

physics: NeverScrollableScrollPhysics()

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


33
投票

错误原因:

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

21
投票

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


14
投票

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

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 上的预览

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

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


8
投票

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

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

8
投票

只需添加

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

6
投票

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

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

6
投票
//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));}))                
                    ),]),

2
投票

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


2
投票

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


2
投票

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


1
投票

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

我认为解决此问题的最佳方法是将您的

TextField
设为
ListView
中的第一项。

因此您不需要列,您的父小部件是

ListView
,其子小部件是
TextField
,后跟您使用
_postBuilder
构建的其余项目。


1
投票
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"),
                 ],
               );
             }),   
           ),
         ],    
     );

1
投票
  body:  SingleChildScrollView(
    physics: ScrollPhysics(),
    child: Column(
          children: [
            getFiltersOnHomePage(),

            SizedBox(
              child: StreamBuilder(
                stream: FirebaseFirestore.instance.collection('posts').snapshots(),
                builder: (context,
                    AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return const Center(
                      child: CircularProgressIndicator(),
                    );
                  }
                  return ListView.builder(
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemCount: snapshot.data!.docs.length,
                      itemBuilder: (ctx, index) => Container(
                            margin: EdgeInsets.symmetric(
                              horizontal: width > webScreenSize ? width * 0.3 : 0,
                              vertical: width > webScreenSize ? 15 : 0,
                            ),
                            child: PostCard(
                              snap: snapshot.data!.docs[index].data(),
                            ),
                          ));
                },
              ),
            ),
           

          ],
        ),
  ),[enter image description here][1]***You will be able to scroll through the page by using Expanded Widget

块引用 使用它您可以滚动整个页面。此页面包含一行和可滚动列内的列表视图构建器。



1
投票

在我的例子中,我添加了一个透明颜色且高度达到 270 的 Container 来解决这个问题。

Column(
  children: <Widget>[
    ListView(
      shrinkWrap: true, // use it
    ),
    Container(
      color: Colors.transparent,
      height: 270.0,
    ),
  ],
)

0
投票

只需在列表视图生成器中使用物理,然后它将可以滚动。

`ListView.builder(

            **physics: ScrollPhysics(),**
              shrinkWrap: true,
              itemCount: rentalTypes.length,
              itemBuilder: (BuildContext context,index){
                String details = rentalTypes[index]['houseDetails'];
                String rent = rentalTypes[index]['rent'];
                return PostItem(image: AssetImage("assets/images/bedroom.jpg"), description: details, price: rent);
              }
              ),`
© www.soinside.com 2019 - 2024. All rights reserved.