I'm new at flutter and I have been searching for proper result of pagination for 2 days.
I followed this code Flutter ListView lazy loading But didn't achieve what I want. Look at below code.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
main() => runApp(InitialSetupPage());
class InitialSetupPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "API Pagination",
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.green),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int pageNum = 1;
bool isPageLoading = false;
List<Map<String, dynamic>> arrayOfProducts;
Future<List<Map<String, dynamic>>> _callAPIToGetListOfData() async {
isPageLoading = true;
final responseDic =
await http.post(urlStr, headers: accessToken, body: paramDic);
Map<String, dynamic> dicOfRes = json.decode(responseDic.body);
List<Map<String, dynamic>> temArr = List<Map<String, dynamic>>.from(dicOfRes["data"]["products"]);
if (pageNum == 1) {
arrayOfProducts = temArr;
} else {
arrayOfProducts.addAll(temArr);
}
return arrayOfProducts;
}
ScrollController controller;
@override
void initState() {
controller = new ScrollController()..addListener(_scrollListener);
super.initState();
}
_scrollListener() {
print(controller.position.extentAfter);
if (controller.position.extentAfter <= 0 && isPageLoading == false) {
_callAPIToGetListOfData().then((data){
setState(() {
});
});
}
}
@override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Online Products"),
centerTitle: true,
),
body: Container(
child: FutureBuilder<List<Map<String, dynamic>>>(
future: _callAPIToGetListOfData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError) {
Text(
'YOu have some error : ${snapshot.hasError.toString()}');
} else if (snapshot.data != null) {
isPageLoading = false;
pageNum++;
print(arrayOfProducts);
return Scrollbar(
child: ListView.builder(
itemCount: arrayOfProducts.length,
controller: controller,
physics: AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
title: Text(
'$index ${arrayOfProducts[index]['title']}'),
);
}),
);
}
}
}),
));
}
}
So, When I reach at bottom of the page my _scrollListener
method get call and there I have set setState(()....
method to reload widget. Issue is I load my actual position and It starts with top of the list. So where I'm going wrong? Actually I want like. https://github.com/istyle-inc/LoadMoreTableViewController/blob/master/screen.gif
Edited:
Final code: (Guide by @Rémi Rousselet)
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
main() => runApp(InitialSetupPage());
class InitialSetupPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "API Pagination",
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.green),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int pageNum = 1;
bool isPageLoading = false;
List<Map<String, dynamic>> arrayOfProducts;
ScrollController controller;
Future<List<Map<String, dynamic>>> future;
int totalRecord = 0;
@override
void initState() {
controller = new ScrollController()..addListener(_scrollListener);
future = _callAPIToGetListOfData();
super.initState();
}
@override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
final constListView = ListView.builder(
itemCount: arrayOfProducts == null ? 0 : arrayOfProducts.length,
controller: controller,
physics: AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Column(
children: <Widget>[
ListTile(
title: Text('$index ${arrayOfProducts[index]['title']}'),
leading: CircleAvatar(backgroundImage: NetworkImage(arrayOfProducts[index]['thumbnail'] ?? "")),
),
Container(
color: Colors.black12,
height: (index == arrayOfProducts.length-1 && totalRecord > arrayOfProducts.length) ? 50 : 0,
width: MediaQuery.of(context).size.width,
child:Center(
child: CircularProgressIndicator()
),
)
],
);
});
return Scaffold(
appBar: AppBar(
title: Text("Online Products"),
centerTitle: true,
),
body: Container(
child: FutureBuilder<List<Map<String, dynamic>>>(
future: future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError) {
Text(
'YOu have some error : ${snapshot.hasError.toString()}');
} else if (snapshot.data != null) {
isPageLoading = false;
print(arrayOfProducts);
return constListView;
}
}
}),
));
}
Future<List<Map<String, dynamic>>> _callAPIToGetListOfData() async {
isPageLoading = true;
final responseDic =
await http.post(urlStr, headers: accessToken, body: paramDic);
Map<String, dynamic> dicOfRes = json.decode(responseDic.body);
List<Map<String, dynamic>> temArr =
List<Map<String, dynamic>>.from(dicOfRes["data"]["products"]);
setState(() {
if (pageNum == 1) {
totalRecord = dicOfRes["total_record"];
print('============>>>>>>> $totalRecord');
arrayOfProducts = temArr;
} else {
arrayOfProducts.addAll(temArr);
}
pageNum++;
});
return arrayOfProducts;
}
_scrollListener() {
if (totalRecord == arrayOfProducts.length) {
return;
}
print(controller.position.extentAfter);
if (controller.position.extentAfter <= 0 && isPageLoading == false) {
_callAPIToGetListOfData();
}
}
}
Thats working but Is it right/good way? little bit confused because if I reach at end of the page and scroll up/down it seems little bit sticky while scrolling..