在可滚动的列中,使用其他小部件的Flutter ListView.Builder()
在可滚动的列中,使用其他小部件的Flutter ListView.Builder()
我有一个TabBarView(),其中包含多个不同的视图。我希望其中一个是一个包含在顶部的TextField和底部的ListView.Builder()的Column,但这两个小部件都应该在同一个可滚动区域(scrollview)中。我实现的方式出现了一些错误:
@override
Widget build(BuildContext context) {
return new Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children:
new Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: new TextField(
decoration: new InputDecoration(
hintText: "在这里输入!"
),
)
),
new ListView.builder(
itemCount: _posts.length, itemBuilder: _postBuilder)
],
);
}
错误:
I/flutter (23520): 在performResize()期间抛出了以下断言:
I/flutter (23520): 垂直视口给出了无限高度。
I/flutter (23520): 视口在滚动方向上扩展以填充其容器。在这种情况下,垂直视口被给予了无限多的垂直空间来扩展。这种情况
I/flutter (23520): 通常发生在可滚动小部件嵌套在另一个可滚动小部件中时。如果此小部件始终嵌套在可滚动小部件中,则无需使用视口,因为
I/flutter (23520): 子项总是有足够的垂直空间。在这种情况下,考虑使用Column。
I/flutter (23520): 否则,考虑使用"shrinkWrap"属性(或ShrinkWrappingViewport)将视口的高度调整为其子项高度的总和。
我阅读了关于将ListView.builder()堆叠在Expanded区域中的方法,但这样会使文本字段变得有点“粘性”,这不是我想要的。:-)
我也遇到了CustomScrollView,但是没有完全理解如何实现它。
使用SingleChildScrollView
可以让子部件滚动。
解决方法
SingleChildScrollView(
child: Column(
children: <Widget>[
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
这里使用了两个属性:
shrinkWrap: true
只占用所需的空间(当有更多项目时仍然可以滚动)。
physics: NeverScrollableScrollPhysics()
这是一个不允许用户滚动的滚动物理属性。意味着只有Column+SingleChildScrollView可以滚动。
谢谢,希望你不要犯和我一样的错误,我在ListView.builder上面加了一个Expanded,最后在十五分钟的沮丧后才意识到。
physics: NeverScrollableScrollPhysics()
解决了我的问题!
Flutter中的ListView.Builder()在可滚动的Column中与其他小部件一起使用时,问题的原因是ListView没有足够的空间来展示其所有的子项。解决方法是将ListView放置在一个Expanded小部件中,这样ListView将占据剩余的空间并可以滚动。
代码示例:
Widget build(BuildContext context) {
return new Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children:
new Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: new TextField(
decoration: new InputDecoration(
hintText: "在这里输入内容!"
),
)
),
new Expanded(
child: ListView.builder(
itemCount: _posts.length,
itemBuilder: _postBuilder
)
)
],
);
}
根据我理解,Expanded和ListView一起使用,因为Expanded会使用剩余的屏幕空间。所以如果你想要一个在Expanded下面的按钮,你需要先有有填充的TextField,然后是Expanded(可以滚动),最后是屏幕底部的按钮。
如果使用这个解决方案时遇到问题,请检查Column是否在Positioned小部件内。如果是的话,你需要指定top和bottom属性,这样Dart才能计算大小。只指定top会导致数据计算错误。
这是正确的方法,并且应该被接受为答案,因为它满足了我们只想要ListView滚动而不是整个页面滚动的需求。
问题的出现的原因是在Flutter中,当使用ListView.builder()构建一个可滚动的列表时,将其放置在可滚动的Column中,会导致列表无法滚动。这是因为Column默认会将其子组件的高度撑满,导致ListView无法获取到滚动的空间。
解决方法是在Column外面包裹一个SingleChildScrollView来解决滚动问题。同时,为了使列表可以正确地展示所有的项,需要在ListView.builder()中添加shrinkWrap: true属性。但是需要注意,添加shrinkWrap属性可能会降低应用程序的性能。
然而,如果在添加shrinkWrap属性后性能变慢了,那么最简单的建议是去掉shrinkWrap属性。
完整的解决方法如下:
SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
mainAxisSize: MainAxisSize.min,
children:
Text('Hey'),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount:18,
itemBuilder: (context,index){
return Text('Some text');
}
)
]
)
)
需要注意的是,如果使用了上述解决方法,可能会导致NotificationListener无法正常工作。
在官方文档中也提到了添加shrinkWrap可能会降低性能的问题,可以通过查看这个链接中的视频获取更多信息。
另外,需要指出的是,上述代码中的错误需要修正。