我正在尝试创建一个滚动列表小部件,它可以显示一些项目,并能够在滚动的底部添加页脚。如果滚动列表没有占据整个高度,比如只有2个条目,那么页脚仍然应该出现在屏幕的底部。第一次我试着计算列表视图所需的垂直尺寸,但这意味着我需要在构建时知道子视图的高度。有更好的方法吗?
编辑
我试图达到与here完全相同的效果,当然是使用Flutter。
bakd9h0s1#
您需要为此创建一个自定义的RenderBox。因为没有现成的小部件支持这个功能。SliverFillRemaining非常接近。但是它的大小调整/滚动行为与您所期望的不同。As,如果存在,几乎总是使Scrollable...可滚动。相反,我们可以复制粘贴SliverFillRemaining的源代码,并进行一些编辑
SliverFillRemaining
Scrollable
class SliverFooter extends SingleChildRenderObjectWidget { /// Creates a sliver that fills the remaining space in the viewport. const SliverFooter({ Key key, Widget child, }) : super(key: key, child: child); @override RenderSliverFooter createRenderObject(BuildContext context) => new RenderSliverFooter(); } class RenderSliverFooter extends RenderSliverSingleBoxAdapter { /// Creates a [RenderSliver] that wraps a [RenderBox] which is sized to fit /// the remaining space in the viewport. RenderSliverFooter({ RenderBox child, }) : super(child: child); @override void performLayout() { final extent = constraints.remainingPaintExtent - math.min(constraints.overlap, 0.0); var childGrowthSize = .0; // added if (child != null) { // changed maxExtent from 'extent' to double.infinity child.layout(constraints.asBoxConstraints(minExtent: extent, maxExtent: double.infinity), parentUsesSize: true); childGrowthSize = constraints.axis == Axis.vertical ? child.size.height : child.size.width; // added } final paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: extent); assert(paintedChildSize.isFinite); assert(paintedChildSize >= 0.0); geometry = new SliverGeometry( // used to be this : scrollExtent: constraints.viewportMainAxisExtent, scrollExtent: math.max(extent, childGrowthSize), paintExtent: paintedChildSize, maxPaintExtent: paintedChildSize, hasVisualOverflow: extent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0, ); if (child != null) { setChildParentData(child, constraints, geometry); } } }
这里我改变了三件事之一
maxExtent
SliverGeometry
scrollExtent
现在我们可以像往常一样在CustomScrollView中使用它。最终结果:
CustomScrollView
new CustomScrollView( slivers: <Widget>[ new SliverFixedExtentList( itemExtent: 42.0, delegate: new SliverChildBuilderDelegate((context, index) { return new SizedBox.expand( child: new Card(), ); }, childCount: 42), ), new SliverFooter( child: new Align( alignment: Alignment.bottomCenter, child: new Container( height: 42.0, color: Colors.red, ), ), ), ], ),
hgqdbh6s2#
这可以通过使用具有特殊约束的SingleChildScrollView来实现,如here所解释的。请看下面的例子:
SingleChildScrollView
@override Widget build(BuildContext context) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { return SingleChildScrollView( child: ConstrainedBox( constraints: constraints.copyWith( minHeight: constraints.maxHeight, maxHeight: double.infinity, ), child: IntrinsicHeight( child: Column( children: <Widget>[ Container(height: 200, color: Colors.blue), Container(height: 200, color: Colors.orange), Container(height: 200, color: Colors.green), Container(height: 50, color: Colors.pink), Expanded( child: Align( alignment: Alignment.bottomCenter, child: Container( width: double.infinity, color: Colors.red, padding: EdgeInsets.all(12.0), child: Text('FOOTER', textAlign: TextAlign.center,), ), ), ), ], ), ), ), ); } ); }
这将生成以下布局:
如果您将粉红色容器的高度更改为更大的值,例如500,您将看到页脚也随整个列表一起滚动。感谢西蒙·莱特富特的帮助,为我指明了正确的方向!
hgtggwj03#
使用生成器在ListView中添加页脚1.只需在itemCount中添加+1,例如:itemCount:list.length + 11.在返回customWidget时,检查条件list.length == index,仅返回SizedBox(height:"required height of footer ")。编码:
itemCount
+1
itemCount:list.length + 1
customWidget
list.length == index
SizedBox(height:"required height of footer ")
ListView.builder( itemCount: list.length+1, physics: BouncingScrollPhysics(), itemBuilder: (context, index) { return GestureDetector( onTap: () { if (list.length == index) { return; } Navigator.push( context, MaterialPageRoute( builder: (context) => PlotDetail(list[index]))); }, child: list.length != index?PlotListItemWidget(list[index]):SizedBox(height: 100,)); }, );
cdmah0mi4#
这里我创建了flat_list小部件,它的规范与React Native的FlatList类似。
FlatList( + listFooterWidget: const Footer(), data: items.value, buildItem: (item, index) { var person = items.value[index]; return ListItemView(person: person); }, ),
4条答案
按热度按时间bakd9h0s1#
您需要为此创建一个自定义的RenderBox。因为没有现成的小部件支持这个功能。
SliverFillRemaining
非常接近。但是它的大小调整/滚动行为与您所期望的不同。As,如果存在,几乎总是使Scrollable
...可滚动。相反,我们可以复制粘贴
SliverFillRemaining
的源代码,并进行一些编辑这里我改变了三件事之一
maxExtent
的约束。因为如果没有更多的屏幕空间可用,将强制页脚的高度为0。SliverGeometry
scrollExtent
从“全屏高度”更改为“实际可用大小”。这样它实际上只 * 填充 * 剩余的可见空间。而不是填充屏幕。scrollExtent
中,等于实际的页脚高度。这样,如果视口中没有剩余空间,则只需添加子对象,周围没有任何间距。现在我们可以像往常一样在
CustomScrollView
中使用它。最终结果:
hgqdbh6s2#
这可以通过使用具有特殊约束的
SingleChildScrollView
来实现,如here所解释的。请看下面的例子:
这将生成以下布局:
如果您将粉红色容器的高度更改为更大的值,例如500,您将看到页脚也随整个列表一起滚动。
感谢西蒙·莱特富特的帮助,为我指明了正确的方向!
hgtggwj03#
使用生成器在ListView中添加页脚
1.只需在
itemCount
中添加+1
,例如:itemCount:list.length + 1
1.在返回
customWidget
时,检查条件list.length == index
,仅返回SizedBox(height:"required height of footer ")
。编码:
cdmah0mi4#
这里我创建了flat_list小部件,它的规范与React Native的FlatList类似。