简体   繁体   中英

Best practices for implementing an infinite scroll GridView in Flutter?

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

And output of the above program as follow
在此处输入图像描述

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM