Flutter仿iOS TableView分组实现
一、背景
Flutter的ListView或CustomScrollView支持的是单列表,无法实现分区分组,所以group_tableview来帮你实现。
二、实现原理
主要功能
| 功能 | 进度及实现 |
|---|---|
| 分组 | plain,group |
| 自定义section header | 支持 |
| 自定义section footer | 支持 |
| 能够添加刷新 | 支持 |
仿iOS group样式
enum ViewStyle {
plain, //regular table view
group //sections are grouped together
}
GroupListView实现原理
///
/// GroupListView 实现
///
class GroupListView extends StatefulWidget {
final ViewStyle style; //listview样式,默认是plain样式
final int numberOfSections; //section个数 默认1
final SectionBuilder numberOfRowsInSection; //每个section内有多少个row
final IndexPathWidgetBuilder itemBuilder; //item builder方法
final IndexedWidgetBuilder sectionHeaderBuilder; // section header builder 方法
final IndexedWidgetBuilder sectionFooterBuilder; // section footer builder 方法
final ScrollController controller; // controller
final Color backgroundColor; // 背景颜色
GroupListView(
{this.itemBuilder,
this.style = ViewStyle.plain,
this.numberOfSections = 1,
this.numberOfRowsInSection,
this.sectionHeaderBuilder,
this.sectionFooterBuilder,
this.controller,
this.backgroundColor})
: assert(itemBuilder != null,"itemBuilder 不能为null");
@override
_GroupListViewState createState() => _GroupListViewState();
}
目前是通过ListView.builer实现
@override
Widget build(BuildContext context) {
_initData();
return ListView.builder(
itemBuilder: _itemBuilder,
itemCount: _calculateItemCount(),
);
}
获取总行数,totalCount = sectionHeader+sectionFooter+rows
int _calculateItemCount() {
return totalCount; //row+section = 总行数
}
根据datasource初始化listview
///根据DataSource 初始化数据
void _initData() {
totalCount = 0;
sectionList.clear();
for (int section = 0; section < widget.numberOfSections; section++) {
//遍历section
int rowCount =
widget.numberOfRowsInSection(section); //获取每个section(区)有多少个row
Widget header; //获取header
if (widget.sectionHeaderBuilder != null) {
header = widget.sectionHeaderBuilder(context, section);
}
Widget footer; //获取footer
if (widget.sectionFooterBuilder != null) {
footer = widget.sectionFooterBuilder(context, section);
}
bool isHaveHeader = header != null ? true : false; //是否有header
bool isHaveFooter = footer != null ? true : false; //是否有footer
SectionModel sectionModel =
SectionModel(section, rowCount, isHaveHeader, isHaveFooter, header);
if (section == 0) {
currentSectionModel = sectionModel;
}
sectionList.add(sectionModel);
totalCount = totalCount +
rowCount +
(header != null ? 1 : 0) +
(footer != null ? 1 : 0); //ListView itemCount总行数
GlobalKey globalKey = GlobalKey(debugLabel: section.toString());
keyList.add(globalKey);
}
listView = ListView.builder(
controller: _controller,
physics: BouncingScrollPhysics(),
itemBuilder: _itemBuilder,
itemCount: _calculateItemCount(),
);
}
ListView.builder渲染每一个row
Widget _itemBuilder(BuildContext context, int index) {
Widget item;
Object model = _getItemRowModel(index);
if (model is SectionHeaderModel) {
SectionHeaderModel sectionHeaderModel = model;
item = widget.sectionHeaderBuilder(context, sectionHeaderModel.section);
}else if(model is SectionFooterModel){
SectionFooterModel sectionFooterModel = model;
item = widget.sectionFooterBuilder(context, sectionFooterModel.section);
} else {
RowModel rowModel = model;
item = widget.itemBuilder(context, rowModel.indexPath);
}
return item;
}
Object _getItemRowModel(int index) {
int passCount = 0;
//遍历整个分区 ,去查找index在哪个分区section的哪个下标row
for (int section = 0; section < sectionList.length; section++) {
SectionModel sectionModel = this.sectionList[section];
bool isHaveHeader = sectionModel.isHaveHeader;
bool isHaveFooter = sectionModel.isHaveFooter;
int tempCount = 0;
if (isHaveHeader == true) {
//有header
tempCount = tempCount + 1;
}
if (index == passCount && isHaveHeader == true) {
//这是header
return SectionHeaderModel(section);
}else if(index == tempCount + sectionModel.rowCount + passCount && isHaveFooter == true){
//这是footer
return SectionFooterModel(section);
} else if (index >= passCount &&
index < tempCount + sectionModel.rowCount+passCount) {
//这是row
IndexPath indexPath = IndexPath(section, index - passCount - tempCount);
return RowModel(indexPath);
}
passCount = passCount + sectionModel.rowCount + tempCount +(isHaveFooter?1:0);
}
return null;
}
效果图
源码github
已同步上传Pub搜索group_tableview
如有帮助,请给个star,谢谢😁😁😁