添加无限滚动到 GridView.builder 以 flutter FutureBuilder

Add infinite scroll to GridView.builder to flutter FutureBuilder

我很难在 flutter 中专注于无限滚动。 我试图先加载 10 个食谱,然后在 ScrollController 的帮助下显示新的食谱。 当没有更多食谱时,我想显示一条消息,表明没有更多帖子。

这是我的项目代码。

import 'package:flutter/material.dart';
import 'package:test/model/recipe.dart';
import 'package:test/pages/recipe_details.dart';
import 'package:test/widgets/recipe_card.dart';
import 'package:http/http.dart' as http;

class SingleCategory extends StatefulWidget {
  final Recipe recipe;
  final int recipeCourseid;
  final String recipeCourseName;

  SingleCategory({
    this.recipe,
    @required this.recipeCourseid,
    @required this.recipeCourseName,
  });

  @override
  _SingleCategoryState createState() => _SingleCategoryState();
}

class _SingleCategoryState extends State<SingleCategory> {
  ScrollController _scrollController = ScrollController();
  int pageNumber = 1;

  var myRecipe;

  Future<List<Recipe>> getRecipeList({int pageNumber}) async {
    // pageNum = 1;
    var response = await http.get(
        'https://test.com/wp-json/wp/v2/wprm_recipe?wprm_course=${widget.recipeCourseid}&per_page=10&$pageNumber');
    var body = response.body;
    final recipes = recipeFromJson(body)

    return recipes;
  }

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        pageNumber++;
        print(pageNumber);
        getRecipeList();
      }
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.rtl,
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.recipeCourseName),
          centerTitle: true,
          elevation: 5,
        ),
        body: Padding(
          padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 12.0),
          child: FutureBuilder(
            future: getRecipeList(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return GridView.builder(
                  controller: _scrollController,
                  itemCount: snapshot.data.length,
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    crossAxisSpacing: 12.0,
                    mainAxisSpacing: 12.0,
                  ),
                  itemBuilder: (BuildContext context, int index) {
                    myRecipe = snapshot.data[index].recipe;
                    return InkWell(
                      onTap: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => RecipeDetails(
                              recipe: snapshot.data[index],
                            ),
                          ),
                        );
                      },
                      child: RecipeCard(myRecipe: myRecipe),
                    );
                  },
                );
              } else if (snapshot.hasError) {
                return Center(
                  child: Text('There was an error, Please try again'),
                );
              } else {
                return Center(
                  child: CircularProgressIndicator(),
                );
              }
            },
          ),
        ),
      ),
    );
  }
}

如果你能指出正确的方向,我将不胜感激。

尝试在您的 GridView 中添加

physics: const AlwaysScrollableScrollPhysics(),

一切看起来都不错,但你必须做一点小改动。

您的代码:

_scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        pageNumber++;
        print(pageNumber);
        getRecipeList();
      }
    });

应该是:

_scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        pageNumber++;
        setState(() {}); // if add this, Reload your futurebuilder and load more data
 //        getRecipeList(); // It's not necessary because, FutureBuilder call automatically getRecipeList when you call setState 
      }
    });

在 class

中声明一个新变量
 List<Recipe> recipesList;

并且在 getRecipeList() 方法内部更改如下

Future<List<Recipe>> getRecipeList({int pageNumber}) async {
    // pageNum = 1;
If(page number ==1)
  recipesList.clear;

    var response = await http.get(
        'https://test.com/wp-json/wp/v2/wprm_recipe?wprm_course=${widget.recipeCourseid}&per_page=10&$pageNumber');
    var body = response.body;
    final recipes = recipeFromJson(body)
    recipesList.addAll(recipes);
    return recipesList;
  }

并在 scrollListener 中尝试传递 pageNumber。由于您在 getRecipesList 方法内外都为 pageNumber 声明了相同的名称。

_scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        pageNumber++;
        print(pageNumber);
        getRecipeList(pageNumber:pageNumber).then((){
            setState((){});
        });
      }
    });