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?


Solution 1: KumarSunil17

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


Solution 2: Ravindra Kushwaha

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 contollerfor 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();
  }
}

And output of the above program as follow
enter image description here