Flutter ListView.Builder() in scrollable Column with other widgets

I have a TabBarView() with an amount of different views. I want of them to be a Column with a TextField at top and a ListView.Builder() below, but both widgets should be in the same scrollable area (scrollview). The way I implemented it threw some errors:

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

Error:

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.

I read about stacking the ListView.builder() in an Expanded-Area but it made the textfield kind of "sticky" which is not what I want. :-)

I also came across CustomScrollView but didn't fully understand how to implement it.

134707 次浏览

Column是不可滚动的,这就是为什么上面的 TextField不会滚动,而下面的 ListView会。

在我看来,解决这个问题的最好办法是让你的 TextField成为你的 ListView中的第一个项目。

So you won't need a column, your parent widget is the ListView, and its children are the TextField followed by the remaining items you build with _postBuilder.

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

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

Reason for the error:

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

Solution

你需要约束 ListView的高度,这样它才能扩展到与 Column匹配,有几种方法可以解决这个问题,我在这里列举几种:


  1. If you want to allow ListView to take up all remaining space inside Column use Flexible.

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

  1. If you want to limit your ListView to certain height, you can use SizedBox.

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

  1. If your ListView is small, you may try shrinkWrap property on it.

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

解决办法如下:

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

使用 变大了小部件在不溢出这些像素的情况下约束:)

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

只要在 Builder ()中添加 物理: NeverScrollableScrollPhysical (),就可以滚动了

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

使用允许子小部件滚动的 SingleChildScrollView

Solution

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

这里使用了两个属性

shrinkWrap: true

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

physics: NeverScrollableScrollPhysics()

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

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

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

ListView.Builder ()中使用 物理: NeverScrollableScrollPhysical ()shrinkWrap: true并享受

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

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

这是飞镖靶上的 预览

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

如果所有列表项都是相同的高度,那么您可以使用 SliverFixedExentList,这样更有效,因为不会动态计算每个子项的高度,但是您必须知道确切的像素高度。您还可以使用 原型扩展列表,其中您提供列表中的第一个项目(原型) ,并且所有其他子项目将使用原型的高度,因此您不需要知道以像素为单位的精确高度。

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

加上

Column(
mainAxisSize: MainAxisSize.max, //Add this line onyour column
children:[
SomeWidget(),
Expanded(child:ListView.builder())
]
)
  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

引用原文 使用这个,您可以滚动整个页面。此页面在可滚动列中包含一行和一个 listview 生成器。


在我的例子中,我添加了一个具有透明颜色和高达270的容器来解决这个问题。

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