I am trying to update my list of Thread
objects when I reach near the end of the screen while scrolling down (to show an infinite list of items while I keep scrolling down)
My current setup is the following:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'dart:async';
import 'dart:convert';
import 'forums.dart';
// Retrieve JSON response forum thread list
Future<List<Thread>> fetchForumThreadList(String url, int page) async {
final response =
await http.get('http://10.0.2.2:8080/frest$url/page/$page');
if (response == null) {
throw new Exception("No site");
}
if (response.statusCode == 200) {
return compute(parseForumThreadList, response.body);
} else {
List<Thread> e = [];
return e;
}
}
List<Thread> parseForumThreadList(String responseBody) {
Map decoded = json.decode(responseBody);
List<Thread> threads = [];
Map threadList = decoded["list"];
for (var thread in threadList["List"]) {
threads.add(Thread(
thread["ID"],
thread["Staff"],
thread["Support"],
thread["Sticky"],
thread["Locked"],
thread["Title"],
thread["Replies"],
thread["Views"],
thread["Author"],
thread["CreatedAt"],
));
}
return threads;
}
// Generate a card list from a List of forum threads
Widget generateForumThreadList(BuildContext context, int index, List<Thread> data) {
// Use custom icon for staff posts
IconData authorIcon = Icons.account_circle;
Color authorIconColor = Color(0xAAFFFFFF);
if (data[index].staff) {
authorIcon = Icons.verified_user;
authorIconColor = Color(0xAAFFBA08);
}
return Column(
children: <Widget>[
InkWell(
onTap: () {
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// We need to wrap columns under Flexible
// To make text wrap if larger than screen width
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 6.0),
child: Text(
data[index].title,
style: TextStyle(
fontSize: 22.0,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(12.0, 1.0, 12.0, 2.0),
// Add thread author and created date
child: Row(
children: <Widget>[
Icon(
authorIcon,
size: 15.0,
color: authorIconColor,
),
Padding(
padding: const EdgeInsets.fromLTRB(5.0, 12.0, 12.0, 12.0),
child: Text(
"Author: " + data[index].author,
),
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(12.0, 1.0, 12.0, 12.0),
// Add threads and posts information
child: Row(
children: <Widget>[
Icon(
Icons.chat_bubble,
size: 15.0,
color: Color(0xAAFFFFFF),
),
Padding(
padding: const EdgeInsets.fromLTRB(5.0, 12.0, 12.0, 12.0),
child: Text(
data[index].replies.toString() + " Replies",
),
),
Icon(
Icons.pageview,
size: 15.0,
color: Color(0xAAFFFFFF),
),
Padding(
padding: const EdgeInsets.fromLTRB(5.0, 12.0, 12.0, 12.0),
child: Text(
data[index].views.toString() + " Views",
),
),
],
),
),
],
),
),
],
),
),
// Add a divider for each forum item
Divider(
height: 4.0,
),
],
);
}
// Class used for a forum thread
class Thread {
final int id;
final bool staff;
final bool support;
final bool sticky;
final bool locked;
final String title;
final int replies;
final int views;
final String author;
final String createdAt;
Thread(
this.id,
this.staff,
this.support,
this.sticky,
this.locked,
this.title,
this.replies,
this.views,
this.author,
this.createdAt,
);
}
class ForumThreadList extends StatefulWidget {
final Forum forum;
ForumThreadList(this.forum);
@override
_ForumThreadListState createState() => _ForumThreadListState(forum);
}
class _ForumThreadListState extends State<ForumThreadList> {
final Forum forum;
int page = 1;
ScrollController controller;
_ForumThreadListState(this.forum);
@override
void initState() {
controller = new ScrollController();
controller.addListener(_scrollListener);
super.initState();
}
@override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
VoidCallback _scrollListener() {
// If we are near the end of the list
if (controller.position.extentAfter < 300) {
page++;
print(page);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(forum.name),
),
body: Scrollbar(
child: Center(
child: FutureBuilder<List<Thread>>(
future: fetchForumThreadList(forum.url, page),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
controller: controller,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext ctx, int index) {
return generateForumThreadList(ctx, index, snapshot.data);
},
);
} else if (snapshot.hasError) {
return Text(snapshot.error);
}
return CircularProgressIndicator();
},
),
),
),
// Add floating button to reload forums
floatingActionButton: new FloatingActionButton(
elevation: 0.0,
child: Icon(
Icons.sync,
size: 32.0,
),
// When pressing the button reload the forum list
onPressed: () { },
),
);
}
}
Right now everything works fine, when I load the application the first page of my API is fetched and the list is populated, however I cant figure how to append the next page of elements when I am near the end of the screen.
I tried updating my page
variable when near the end thinking that this would make the FutureBuilder
update, but this does not seem to be correct and I also think this wont give me my desired result (making the list expand instead of replacing items with a new batch).