Reputation: 13
I'm having a hard time to wrap my head around infinite scrolling in flutter. I'm trying to load 10 recipes first, then with the help of ScrollController show the new recipes. and when there is no more recipes left, I want to show a message that shows there is no more posts.
here's my project's code.
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(),
);
}
},
),
),
),
);
}
}
I would apprecite it if you could point me to the right direction.
Upvotes: 0
Views: 4210
Reputation: 439
Declare a new variable in your class
List<Recipe> recipesList;
And inside the getRecipeList() method change as like below
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;
}
And in the scrollListener try to pass pageNumber. Since you have declare the same name for pageNumber both inside and outside getRecipesList method.
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
print(pageNumber);
getRecipeList(pageNumber:pageNumber).then((){
setState((){});
});
}
});
Upvotes: 0
Reputation: 1783
Everything looks good but you have to make a small change.
Your Code:
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
print(pageNumber);
getRecipeList();
}
});
Should be:
_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
}
});
Upvotes: 1
Reputation: 14775
Try to add in your GridView
physics: const AlwaysScrollableScrollPhysics(),
Upvotes: 1