【问题标题】:Best practices for implementing an infinite scroll GridView in Flutter?Flutter中实现无限滚动GridView的最佳实践?
【发布时间】:2020-05-10 05:27:38
【问题描述】:

我想创建一个 GridView 来显示将从服务器获取的项目的偏移量。我在 GridView 中只加载了 10 个项目,当用户滚动到 10 个后,我将加载更多的 10 个项目。在 Flutter 中实现无限滚动 GridView 的最佳实践是什么?

【问题讨论】:

    标签: flutter


    【解决方案1】:

    您需要在ListViewGridView 的底部添加ScrollController 用于滚动检测。由于您需要GridView,我创建了ScrollController 列表器并添加到GridView'scontoller 以检测滚动。我已经创建了它的演示,请检查一次。第一次加载 10 个项目,当列表到达底部时,它会在其中添加更多 10 个项目。

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

    上述程序的输出如下

    【讨论】:

    • 如果 API 响应少于 10 项怎么办?
    【解决方案2】:
    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();
            });
      }
    }
    

    谢谢

    【讨论】:

      猜你喜欢
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 2020-05-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多