如何在Flutter的ReorderableListView中添加Footer组件
给ReorderableListView添加底部组件的解决方案
我懂你现在的困扰——ReorderableListView只提供了header属性,却没有直接的footer配置项,不过咱们通过简单的布局嵌套就能搞定这个需求,下面给你两种常见场景的实现方案:
方案一:固定在页面底部的Footer
这种方案下,Footer会始终停留在页面底部,不会随着列表滚动,适合做页面级的底部导航或版权信息:
import 'package:flutter/material.dart'; class MyStickyHeader extends StatefulWidget { @override State<StatefulWidget> createState() { return _MyStickyHeaderState(); } } class _MyStickyHeaderState extends State<MyStickyHeader> { List<Widget> _list = [ Text("Apple"), Text("Ball"), Text("Cat"), Text("Dog"), Text("Elephant") ]; @override Widget build(BuildContext context) { return Container( margin: EdgeInsets.only(top: 30, left: 10), color: Colors.white, child: showData(), ); } Widget showData() { return Column( children: [ // 原来的Header组件 Container( height: 100, color: Colors.red, ), // 用Expanded包裹ReorderableListView,让它填充剩余空间 Expanded( child: ReorderableListView( children: _list .map((item) => Container( padding: EdgeInsets.all(10), key: Key("${(item as Text).data}"), child: Row( children: <Widget>[ Icon(Icons.ac_unit), Expanded( child: item, ) ], ), )) .toList(), onReorder: (int start, int current) { // 你的重排序逻辑保持不变 if (start < current) { int end = current - 1; Widget startItem = _list[start]; int i = 0; int local = start; do { _list[local] = _list[++local]; i++; } while (i < end - start); _list[end] = startItem; } if (start > current) { Widget startItem = _list[start]; for (int i = start; i > current; i--) { _list[i] = _list[i - 1]; } _list[current] = startItem; } setState(() {}); }, ), ), // 新增的Footer组件 Container( height: 80, color: Colors.blue, alignment: Alignment.center, child: Text("这是底部固定的Footer", style: TextStyle(color: Colors.white)), ), ], ); } }
方案二:随列表滚动的Footer
如果希望Footer作为列表的一部分,跟着列表滚动到页面底部,并且不允许用户拖动它,可以把Footer作为ReorderableListView的最后一个子项,并用AbsorbPointer阻止拖动:
import 'package:flutter/material.dart'; class MyStickyHeader extends StatefulWidget { @override State<StatefulWidget> createState() { return _MyStickyHeaderState(); } } class _MyStickyHeaderState extends State<MyStickyHeader> { List<Widget> _list = [ Text("Apple"), Text("Ball"), Text("Cat"), Text("Dog"), Text("Elephant") ]; @override Widget build(BuildContext context) { return Container( margin: EdgeInsets.only(top: 30, left: 10), color: Colors.white, child: showData(), ); } Widget showData() { // 把Footer加入列表(注意要放在最后,且设置唯一Key) List<Widget> listWithFooter = [..._list, Text("Footer")]; return ReorderableListView( header: Container( height: 100, color: Colors.red, ), children: listWithFooter .map((item) { // 判断是否是Footer项 bool isFooter = (item as Text).data == "Footer"; return AbsorbPointer( // 对Footer禁用拖动 absorbing: isFooter, child: Container( padding: EdgeInsets.all(10), key: Key("${(item as Text).data}"), // 给Footer加个不同的样式区分 color: isFooter ? Colors.blue : Colors.transparent, alignment: isFooter ? Alignment.center : Alignment.centerLeft, child: Row( children: <Widget>[ if (!isFooter) Icon(Icons.ac_unit), Expanded( child: Text( (item as Text).data!, style: isFooter ? TextStyle(color: Colors.white) : null, ), ) ], ), ), ); }) .toList(), onReorder: (int start, int current) { // 重排序时排除Footer项的位置 if ((start == listWithFooter.length - 1) || (current > listWithFooter.length - 1)) { return; } // 调整索引,因为Footer在最后,实际可排序的是前5项 int actualStart = start < listWithFooter.length -1 ? start : start -1; int actualCurrent = current < listWithFooter.length -1 ? current : current -1; // 你的重排序逻辑保持不变 if (actualStart < actualCurrent) { int end = actualCurrent - 1; Widget startItem = _list[actualStart]; int i = 0; int local = actualStart; do { _list[local] = _list[++local]; i++; } while (i < end - actualStart); _list[end] = startItem; } if (actualStart > actualCurrent) { Widget startItem = _list[actualStart]; for (int i = actualStart; i > actualCurrent; i--) { _list[i] = _list[i - 1]; } _list[actualCurrent] = startItem; } setState(() {}); }, ); } }
关键说明
- 方案一通过
Column+Expanded的组合,让ReorderableListView占据中间的滚动区域,Footer固定在底部,适合页面级的固定底部元素 - 方案二把Footer作为列表的一部分,通过
AbsorbPointer禁止拖动,同时在重排序逻辑里排除Footer的位置,保证它始终在列表最后 - 两种方案都保持了你原有的重排序逻辑,只需要根据你的实际需求选择即可
内容的提问来源于stack exchange,提问作者jazzbpn
相关产品推荐
相关产品推荐

