I want to create a GridView that displays items which will be fetching from server by offset. I load only 10 items in GridView, and after user scroll reached to 10, I will load more 10 items. What are the best practices for implementing an infinite scroll GridView in Flutter?
You need to add the ScrollController
for the scrolling detection at the bottom for the ListView
and GridView
. As you need the GridView
i have created the ScrollController
listner and added to the GridView's
contoller
for the detection of the scroll. I have created the demo of it, please check it once. At first time it load the 10 items and when list comes to the bottom then it add more 10 items in it.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return HomeState();
}
}
class HomeState extends State<HomeScreen> {
List dataList = new List<int>();
bool isLoading = false;
int pageCount = 1;
ScrollController _scrollController;
@override
void initState() {
super.initState();
////LOADING FIRST DATA
addItemIntoLisT(1);
_scrollController = new ScrollController(initialScrollOffset: 5.0)
..addListener(_scrollListener);
}
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gridview',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.red,
accentColor: Color(0xFFFEF9EB),
),
home: Scaffold(
appBar: new AppBar(),
body: GridView.count(
controller: _scrollController,
scrollDirection: Axis.vertical,
crossAxisCount: 2,
mainAxisSpacing: 10.0,
physics: const AlwaysScrollableScrollPhysics(),
children: dataList.map((value) {
return Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height * 0.2,
margin: EdgeInsets.only(left: 10.0, right: 10.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: Text("Item ${value}"),
);
}).toList(),
)));
}
//// ADDING THE SCROLL LISTINER
_scrollListener() {
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
print("comes to bottom $isLoading");
isLoading = true;
if (isLoading) {
print("RUNNING LOAD MORE");
pageCount = pageCount + 1;
addItemIntoLisT(pageCount);
}
});
}
}
////ADDING DATA INTO ARRAYLIST
void addItemIntoLisT(var pageCount) {
for (int i = (pageCount * 10) - 10; i < pageCount * 10; i++) {
dataList.add(i);
isLoading = false;
}
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
}
class AllOrdersPage extends StatefulWidget {
@override
_AllOrdersPageState createState() => _AllOrdersPageState();
}
class _AllOrdersPageState extends State<AllOrdersPage> {
List<OrderDatum> ordersList;
ScrollController _scrollController = ScrollController();
int skip = 0;
bool shouldLoadMore = true;
Future<OrdersResponse> future;
@override
void initState() {
super.initState();
ordersList = [];
future = getAllOrders(skip); //load data for first time
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) { //Check whether user scrolled to last position
if (shouldLoadMore) {
setState(() {
skip += ordersList.length;
future = getAllOrders(skip); //load more data
});
}
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<OrdersResponse>(
future: future,
builder: (context, snapshot) {
if (snapshot.hasError)
return ErrorText('${snapshot.error.toString()}');
if (snapshot.hasData) {
skip = snapshot.data.skip;
if (snapshot.data.limit + snapshot.data.skip >=
snapshot.data.total) {
shouldLoadMore = false;
}
snapshot.data.data.forEach((element) {
if (!ordersList.contains(element)) ordersList.add(element);
});
if (skip == 0 && ordersList.isEmpty) {
return ErrorText('No orders.');
}
return Scrollbar(
controller: _scrollController,
isAlwaysShown: true,
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
childAspectRatio: 2.5,
mainAxisSpacing: 8),
controller: _scrollController,
padding: const EdgeInsets.all(8),
itemBuilder: (BuildContext context, int index) {
if (index == ordersList.length) {
return shouldLoadMore
? Center(child: CircularProgressIndicator())
: Container();
}
return Container(
width: MediaQuery.of(context).size.width,
child: OrderCard(ordersList[index]));
},
itemCount: ordersList.length + 1,
),
);
}
return Loader();
});
}
}
Thanks
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.