FlutterArtist Pagination Davi table Infinite Scroll Ex1
DAVI, short for “Data View”, is a Flutter library available on pub.dev that helps developers build complex data tables while remaining lightweight and easy to use. Davi is used in many FlutterArtist Demo examples, especially those related to displaying data tables.
FaDaviTable is a wrapper widget built around Davi, designed to simplify integration and interaction with FlutterArtist.
In this article, we will use FaDaviTable to build an infinite scrolling table. Whenever the user scrolls to the end of the table, additional data will be loaded automatically.
- FlutterArtist Davi Table (***)

- Download FlutterArtist Demo
2. Country61aShelf
Country61aBlock is configured so that a maximum of 20 ITEM(s) are loaded per query.
country61a_shelf.dart
class Country61aShelf extends Shelf {
@override
ShelfStructure defineShelfStructure() {
return ShelfStructure(
filterModels: {},
blocks: [
Country61aBlock(
name: Country61aBlock.blkName,
description: null,
config: BlockConfig(
pageable: Pageable(pageSize: 20),
),
filterModelName: null,
formModel: null,
childBlocks: [],
itemSortCriteria: null,
),
],
);
}
Country61aBlock findCountry61aBlock() {
return findBlock(Country61aBlock.blkName) as Country61aBlock;
}
}3. Country61aDaviTableItemsView
When the user scrolls to the last row of the table, a Trailing widget will appear to indicate that the next set of data is being loaded.

_trailingWidget()
Widget? _trailingWidget() {
PaginationInfo? pagination = block.paginationInfo;
if (pagination == null) {
return null;
}
if (pagination.currentPage < pagination.totalPages) {
return Text("Loading...");
}
return null;
}No ADS
You need to load the next page of data inside the onTrailingWidget() callback.
Future<void> _onTrailingWidget(bool visible) async {
PaginationInfo? pagination = block.paginationInfo;
if (pagination == null) {
return;
}
if (visible && pagination.currentPage < pagination.totalPages) {
// Delay 1 second to see Trailing widget longer.
await Future.delayed(Duration(seconds: 1));
await _loadMore();
}
}Future<void> _loadMore() async {
await block.queryMore();
}Below is the complete implementation of Country61aDaviTableItemsView, demonstrating how to build an infinite scrolling data table by combining Davi, FaDaviTable, and the FlutterArtist pagination mechanism.
country61a_davi_table_items_view.dart
class Country61aDaviTableItemsView extends BlockItemsView<Country61aBlock> {
final Color? selectedColor = Colors.lightGreen.withAlpha(100);
final Color? currentColor = Colors.lightGreen;
final Color? hoverColor = Colors.greenAccent.withAlpha(30);
final formatter = NumberFormat("###,###,###", "en_US");
Country61aDaviTableItemsView({
required super.block,
super.key,
});
//
// Davi Tutorials:
// https://caduandrade.github.io/davi_flutter_demo/
//
@override
Widget buildContent(BuildContext context) {
return Container(
padding: EdgeInsets.only(right: 0),
child: DaviTheme(
data: _daviThemeData(),
child: FaDaviTable<String, CountryInfo>(
items: block.items,
getItemId: block.getItemId,
sortRuleSide: SortRuleSide.blockSide,
modelSettings: FaDaviTableModelSettings<CountryInfo>(
ignoreDataComparators: true,
sortingMode: SortingMode.disabled,
columns: [
DaviColumn(
name: 'Image',
resizable: false,
width: 60,
cellWidget: (param) {
return Center(
child: ImageUrlView(
imageUrl: param.data.imageUrl,
size: 30,
boxShape: BoxShape.rectangle,
),
);
},
),
DaviColumn(
name: 'Name In English',
grow: 1,
cellValue: (param) {
return param.data.nameInEnglish;
},
),
DaviColumn(
name: 'Population',
width: 100,
cellAlignment: Alignment.centerRight,
cellValue: (param) {
return param.data.population;
},
cellValueStringify: _formatNumber,
),
DaviColumn(
name: 'Area (Km2)',
width: 100,
cellAlignment: Alignment.centerRight,
cellValue: (param) {
return param.data.area;
},
cellValueStringify: _formatNumber,
),
],
),
visibleRowsCount: 10,
// IMPORTANT: For Infinite Scroll Pagination.
trailingWidget: _trailingWidget(),
// IMPORTANT: For Infinite Scroll Pagination.
onTrailingWidget: _onTrailingWidget,
onRowTap: (CountryInfo countryInfo) {
_setCountryAsCurrent(countryInfo);
},
rowColor: (param) {
CountryInfo item = param.data;
bool selected = block.isSelectedItem(item);
bool current = block.isCurrentItem(item);
if (current) {
return currentColor;
} else if (selected) {
return selectedColor;
}
return null;
},
),
),
);
}
Widget? _trailingWidget() {
PaginationInfo? pagination = block.paginationInfo;
if (pagination == null) {
return null;
}
if (pagination.currentPage < pagination.totalPages) {
return Text("Loading...");
}
return null;
}
Future<void> _onTrailingWidget(bool visible) async {
PaginationInfo? pagination = block.paginationInfo;
if (pagination == null) {
return;
}
if (visible && pagination.currentPage < pagination.totalPages) {
// Delay 1 second to see Trailing widget longer.
await Future.delayed(Duration(seconds: 1));
await _loadMore();
}
}
Future<void> _loadMore() async {
await block.queryMore();
}
String _formatNumber(dynamic value) {
return formatter.format(value);
}
DaviThemeData _daviThemeData() {
return DaviThemeData(
columnDividerThickness: 0.4,
columnDividerFillHeight: true,
decoration: BoxDecoration(
border: Border.all(
width: 0.2,
color: Colors.grey,
),
),
scrollbar: TableScrollbarThemeData(
horizontalOnlyWhenNeeded: true,
verticalOnlyWhenNeeded: true,
),
header: HeaderThemeData(),
headerCell: HeaderCellThemeData(
padding: EdgeInsets.all(5),
height: 30,
),
row: RowThemeData(
dividerThickness: 0.4,
fillHeight: true,
color: null,
hoverBackground: (int row) {
if (block.isCurrentIndex(row)) {
return currentColor;
} else if (block.isSelectedIndex(row)) {
return selectedColor;
} else {
return hoverColor;
}
},
),
cell: CellThemeData(
padding: EdgeInsets.all(5),
contentHeight: 30,
),
);
}
Future<void> _setCountryAsCurrent(CountryInfo countryInfo) async {
FlutterArtist.codeFlowLogger.addMethodCall(
ownerClassInstance: this,
currentStackTrace: StackTrace.current,
parameters: {"countryInfo": countryInfo},
);
//
await block.refreshItemAndSetAsCurrent(
item: countryInfo,
);
}
}No ADS
FlutterArtist
- Basic concepts in Flutter Artist
- FlutterArtist Block ex1
- FlutterArtist Filter Example
- FlutterArtist FilterModel MultiOptFilterCriterion ex1
- FlutterArtist FilterInput Example 1
- FlutterArtist Form ex1
- The idea of designing filter models in FlutterArtist
- FlutterArtist FormModel.patchFormFields() Ex1
- FlutterArtist BlockQuickItemUpdateAction Example
- FlutterArtist BlockNumberPagination Ex1
- FlutterArtist GridView Infinite Scroll Example
- FlutterArtist BlockQuickMultiItemCreationAction Example
- FlutterArtist ListView Infinite Scroll Pagination Example
- FlutterArtist Pagination
- FlutterArtist Sort DropdownSortPanel Example
- FlutterArtist Dio
- FlutterArtist BlockBackendAction Example
- FlutterArtist BackgroundWebDownloadAction Example
- FlutterArtist StorageBackendAction ex1
- FlutterArtist Block External Shelf Event ex1
- FlutterArtist Filter FormBuilderMultiDropDown Ex1
- FlutterArtist Master-detail Blocks ex1
- FlutterArtist Scalar ex1
- FlutterArtist Pagination Davi table Infinite Scroll Ex1
- FlutterArtist Filter Tree FormBuilderField ex1
- FlutterArtist Filter FormBuilderRadioGroup ex1
- FlutterArtist Form Parent-child MultiOptFormProp ex1
- FlutterArtist Manual Sorting ReorderableGridView Example
- FlutterArtist Manual Sorting ReorderableListView
- FlutterArtist Scalar External Shelf Event ex1
- FlutterArtist Code Flow Viewer
- FlutterArtist Log Viewer
- FlutterArtist config
- FlutterArtist StorageStructure
- FlutterArtist Debug Storage Viewer
- FlutterArtist DebugMenu
- FlutterArtist Debug UI Components Viewer
- FlutterArtist Debug Shelf Structure Viewer
- FlutterArtist Context Provider Views
- FlutterArtist FilterModelStructure ex1
- FlutterArtist FilterModelStructure ex2
- FlutterArtist FilterModelStructure ex3
- FlutterArtist Internal Shelf Event ex1
- FlutterArtist Deferring External Shelf Events (Ex1)
- FlutterArtist DropdownSortPanel
Show More

