Flutter mimics iOS TableView group implementation

The background,

Flutter’s ListView or CustomScrollView supports a single column table and cannot be partited into groups, so group_tableView will help you do this.

Two, the implementation principle

The main function

function Progress and Implementation
grouping Plain, group
Custom section Headers support
Custom section Footer support
Ability to add refreshes support

Emulate the iOS Group style

enum ViewStyle {
  plain, //regular table view
  group //sections are grouped together
}
Copy the code

Implementation principle of GroupListView

/// /// GroupListView implementation // class GroupListView extends StatefulWidget {final ViewStyle style; // ListView style, default is plain style final int numberOfSections; // Number of sections Default 1 Final SectionBuilder numberOfRowsInSection; // How many row Final IndexPathWidgetBuilder itemBuilder are in each section; // Final IndexedWidgetBuilder sectionHeaderBuilder; // Section Header Builder method Final IndexedWidgetBuilder sectionFooterBuilder; // Section Footer Builder method 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 cannot be null); @override _GroupListViewState createState() => _GroupListViewState(); }Copy the code

This is currently implemented through listView.builer

@override
  Widget build(BuildContext context) {
    _initData();
    return ListView.builder(
      itemBuilder: _itemBuilder,
      itemCount: _calculateItemCount(),
    );
  }
Copy the code

TotalCount = sectionHeader+sectionFooter+rows

int _calculateItemCount() { return totalCount; //row+section = total rows}Copy the code

Initialize the ListView according to the datasource

Void _initData() {totalCount = 0; sectionList.clear(); for (int section = 0; section < widget.numberOfSections; Section++) {/ / traversal section int rowCount = widget. The numberOfRowsInSection (section); // Get the number of row Widget headers per section; / / get the header if (widget sectionHeaderBuilder! = null) { header = widget.sectionHeaderBuilder(context, section); } Widget footer; / / get the footer if (widget sectionFooterBuilder! = null) { footer = widget.sectionFooterBuilder(context, section); } bool isHaveHeader = header ! = null ? true : false; Header bool isHaveFooter = footer! = null ? true : false; 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 Total number of rows GlobalKey GlobalKey = GlobalKey(debugLabel: section.toString()); keyList.add(globalKey); } listView = ListView.builder( controller: _controller, physics: BouncingScrollPhysics(), itemBuilder: _itemBuilder, itemCount: _calculateItemCount(), ); }Copy the code

Listview. builder renders each 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; Row (int section = 0; row (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) {// Have header tempCount = tempCount + 1; } if (index == passCount && isHaveHeader == true) {// This is header return SectionHeaderModel(section); }else if(index == tempCount + sectionModel.rowCount + passCount && isHaveFooter == true){// This is 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; }Copy the code

rendering

Source making

Group_tableview has been uploaded to Pub

If there is any help, please give a star, thanks 😁😁😁