i tried to load more data when scroll. But loadMore function not work. When debugging it stop loadMore function and Scroll not working. Can anyone help me?. I did not find a soluton. Why loadMore not work? What I want to do is load more data when scroll end, page number increases
My api class
static Future<List<Category>> fetchCategories(String path,int pageNumber, int pageSize) async {
late List<Category> list;
final http = InterceptedHttp.build(interceptors: [
ApiInterceptor(),
]);
final response =
await http.get(Uri.parse(path + "?pageNumber=$pageNumber&pageSize=$pageSize"));
print(response);
var responseJson = json.decode(response.body);
var rest = responseJson['data'] as List;
if (response.statusCode == 200) {
print(rest);
list = rest.map<Category>((json) => Category.fromJson(json)).toList();
print("List Size: ${list.length}");
return list;
} else {
throw Exception(response.statusCode);
}
}
}
My View class
import 'package:flutter/material.dart';
import 'package:healtie/core/models/category/category_api.dart';
import 'package:healtie/core/utility/constants.dart';
import '../../../core/config/app_config.dart';
import '../../../core/models/category/category.dart';
import 'categoryCard.dart';
class BuildCategories extends StatefulWidget {
const BuildCategories({Key? key}) : super(key: key);
@override
_BuildCategoriesState createState() => _BuildCategoriesState();
}
class _BuildCategoriesState extends State<BuildCategories> {
late final _baseUrl =
AppConfig.of(context)!.baseURL + AppConfig.of(context)!.categoryPath;
// At the beginning, we fetch the first 10 posts
int _pageNumber = 0;
int _pageSize = 12;
// There is next page or not
bool _hasNextPage = true;
// Used to display loading indicators when _firstLoad function is running
bool _isFirstLoadRunning = false;
// Used to display loading indicators when _loadMore function is running
bool _isLoadMoreRunning = false;
// This holds the posts fetched from the server
List<Category> _categories = [];
late ScrollController _controller;
void _firstLoad() async {
setState(() {
_isFirstLoadRunning = true;
});
try {
var data =
await CategoryApi.fetchCategories(_baseUrl, _pageNumber, _pageSize);
setState(() {
data.forEach((element) {
_categories.add(element);
print("saaa");
});
});
} catch (err) {
print(err);
}
setState(() {
_isFirstLoadRunning = false;
print("asaaa");
});
}
void _loadMore() async {
if (_hasNextPage == true &&
_isFirstLoadRunning == false &&
_isLoadMoreRunning == false &&
_controller.position.extentAfter < 300) {
print(_isFirstLoadRunning);
setState(() {
_isLoadMoreRunning = true; // Display a progress indicator at the bottom
});
_pageNumber += 1; // Increase _page by 1
try {
var fetchedCategories =
await CategoryApi.fetchCategories(_baseUrl, _pageNumber, _pageSize);
print("oldu");
if (fetchedCategories.length > 0) {
setState(() {
_categories.addAll(fetchedCategories);
});
} else {
setState(() {
_hasNextPage = false;
});
}
print("oldu");
} catch (err) {
print(err);
}
setState(() {
_isLoadMoreRunning = false;
});
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) => _firstLoad());
_controller = ScrollController()..addListener(_loadMore);
}
@override
void dispose() {
_controller.removeListener(_loadMore);
super.dispose();
}
@override
Widget build(BuildContext context) {
return _isFirstLoadRunning
? Center(
child: CircularProgressIndicator(),
)
: Column(
children: [
GridView.builder(
controller: _controller,
itemCount: _categories.length,
scrollDirection: Axis.vertical,
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.only(
left: padding, right: padding, top: 10, bottom: 10),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
mainAxisExtent: 120,
),
itemBuilder: (_, index) {
var store = _categories[index];
return CategoryCard(
store: store,
index: index,
);
}),
if (_isLoadMoreRunning == true)
const Padding(
padding: EdgeInsets.only(top: 10, bottom: 40),
child: Center(
child: CircularProgressIndicator(),
),
),
// When nothing else to load
if (_hasNextPage == false)
Container(
padding: const EdgeInsets.only(top: 30, bottom: 40),
color: Colors.amber,
child: const Center(
child: Text('You have fetched all of the content'),
),
),
],
);
}
}
App Page
I use this method for pagination in my projects: First you get the total page and current page in your response like this:
{
"success": true,
"code": 200,
"result":[your response],
"pageNumber": 0,
"totalPage": 0
}
And in your code :
class _BuildCategoriesState extends State<BuildCategories> {
List items = []; //list of your items
bool loadMore = false; //load more data
int page=1;
int totalPage=1;
void getItems(int page) {
//fetch your data and set total page and current page here to handle your paignation
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(child:
NotificationListener(
onNotification: (ScrollNotification notification) {
if (!loadMore && notification.metrics.extentAfter == 0 && page != totalpage) {
setState(() => loadMore = true);
page++;
//send request to server for more data
getitems();
}
return false;
},
child: GridView.count(
children: List.generate(items.length, (int index) {
return Your_Widget_Item()
}),
),
)),
Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.only(bottom: 15),
child: Container(
height: loadMore ? 20.0 : 0,
width: 20,
child: CircularProgressIndicator(
),
),
),
),
]
)
}
}
I hope this code help you to get total idea about handling pagination