Text widget not updating inside StreamBuilder - flutter

I am getting a QuerySnapShot from a Firestore subcollection inside a StreamBuilder from another query, as follows:
//ver fuegos
var estePost = listaFiltrada[indexPost].post_id;
int numero_fuegos = 0;
FirebaseFirestore.instance
.collection('posts')
.doc(estePost)
.collection('fuegos')
.get()
.then((value) => {
if (value.size > 0)
{
setState(() {
numero_fuegos = value.size;
}),
print("tiene fuegos: " +
numero_fuegos.toString()),
}
else
{
setState(() {
numero_fuegos = value.size;
}),
}
});
There are 3 items for value.size.
Here you have the print output:
I/flutter (29797): tiene fuegos: 3
The issue is that putting the variable numero_fuegos inside a text widget, the output is always 0.
EDIT:
class ListaPosts extends StatefulWidget {
#override
_ListaPostsState createState() => _ListaPostsState();
}
class _ListaPostsState extends State<ListaPosts> {
String _miId = "";
#override
initState() {
// TODO: implement initState
super.initState();
FirebaseAuth.instance.idTokenChanges().listen((User user) {
if (user == null) {
} else {
setState(() {
_miId = user.uid;
});
}
});
}
#override
Widget build(BuildContext context) {
final postsProvider = Provider.of<PostsProvider>(context);
return Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.only(top: 0.0),
child: Column(
children: [
StreamBuilder<List<Post>>(
stream: postsProvider.posts,
builder: (context, snapshot) {
if (snapshot.data != null &&
snapshot.data.isNotEmpty &&
ConnectionState.done != null) {
List<Post> listaInicial = snapshot.data;
List<Post> listaFiltrada = [];
listaFiltrada = listaInicial;
return Padding(
padding: const EdgeInsets.all(0.0),
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 140,
child: ListView.builder(
itemCount: listaFiltrada.length,
itemBuilder: (context, indexPost) {
bool es_ambassador = listaFiltrada[indexPost]
.post_autor_is_ambassador;
//ver fuegos
var estePost = listaFiltrada[indexPost].post_id;
int numero_fuegos = 0;
FirebaseFirestore.instance
.collection('posts')
.doc(estePost)
.collection('fuegos')
.get()
.then((value) => {
if (value.size > 0)
{
numero_fuegos = value.size,
print("tiene fuegos: " +
numero_fuegos.toString()),
print("tiene fuegos: " +
value.size.toString()),
}
else
{
setState(() {
numero_fuegos = value.size;
}),
}
});
And that is the Stream:
//Get Posts Entries
Stream<List<Post>> getPosts() {
return _db
.collection('posts')
.orderBy("post_fecha", descending: true)
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) => Post.fromJson(doc.data())).toList());
}

Related

multiselection list view with data from DB

I am trying to read data from postgresql, display in listview, select (single/multiple) displayed items and process further. Able to do with sample data but while displaying data from Postgres DB facing challenges at highlighted area. Any suggestions would be appreciated.
(I am trying to read data from postgresql, display in listview, select (single/multiple) displayed items and process further. Able to do with sample data but while displaying data from Postgres DB facing challenges at highlighted area. Any suggestions would be appreciated.)
**app_db.dart**
import 'package:postgres/postgres.dart';
class AppDatabase {
PostgreSQLConnection? connection;
PostgreSQLResult? _fetchSellerDataResult;
AppDatabase() {
connection = (connection == null || connection!.isClosed == true
? PostgreSQLConnection("10.0.2.2", 5432, "dev", username: "postgres", password: "admin")
: connection);
fetchDataFuture = [];
}
// Fetch Data Section
List<dynamic> fetchDataFuture = [];
Future<List<dynamic>> fetchSellerData() async {
try {
await connection!.open();
await connection!.transaction((fetchDataConn) async {
_fetchSellerDataResult = await fetchDataConn.query(
"select cust_id, cust_name, mmt, available_amount, false AS isSelected from api_positionstest2",
allowReuse: false,
timeoutInSeconds: 30,
);
if (_fetchSellerDataResult!.affectedRowCount > 0) {
fetchDataFuture = _fetchSellerDataResult!.toList(growable: true);
} else {
fetchDataFuture = [];
} });
} catch (exc) {
fetchDataFuture = [];
exc.toString();
}
return fetchDataFuture;
}}
**model_positions.dart**
import 'package:e2/Models/app_db.dart';
class ModelsPositions {
List<dynamic> sellerDataFuture = [];
Future<List<dynamic>> fetchSellerData() async {
sellerDataFuture = await AppDatabase().fetchSellerData();
return sellerDataFuture;
}}
**MasterPositions.dart**
class MasterPositions {
String custID;
String custName;
double mtm;
double availableCash;
bool isSelected = false;
MasterPositions(
{required this.custID,
required this.custName,
required this.mtm,
required this.availableCash});}
**master_control.dart**
import 'package:flutter/material.dart';
import 'package:e2/Models/model_positions.dart';
class MasterControl extends StatefulWidget {
const MasterControl({super.key});
#override
State<MasterControl> createState() => _MasterControlState();
}
class _MasterControlState extends State<MasterControl> {
List<MasterPositions> selectedContacts = [];
List<MasterPositions> fetchedPositions = [];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => Scaffold(
body: FutureBuilder<List<dynamic>>(
future: ModelsPositions().fetchSellerData(),
builder: (context, snapshot) {
final positions = snapshot.data ?? [];
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
if (snapshot.hasError) {
return Center(child: Text('Error while loading Master Positions screen'));
} else {
return buildPositions(positions);
} } }), );
Widget buildPositions(List<dynamic> positions) {
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: positions.length,
itemBuilder: (context, index) {
final pos = positions[index];
final custID = pos.elementAt(0).toString();
final custName = pos.elementAt(1).toString();
final mtm = double.tryParse(pos.elementAt(2)) ?? 0.0;
final availableCash = double.tryParse(pos.elementAt(3)) ?? 0.0;
final isSelected = pos.elementAt(4);
return ListTile(
horizontalTitleGap: -5,
title: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(custID),
const SizedBox(height: 5),
Text(custName)],),),],),),
leading: isSelected
? Icon( Icons.check_circle, color: Colors.green[700],)
: const Icon(Icons.check_circle_outline, color: Colors.grey,),
onTap: () {
setState(() {
positions[index].elementAt(4) = !positions[index].elementAt(4); `**--> suggestion needed here**`
if (positions[index] == true) {
selectedContacts.add(
MasterPositions(custID: custID, custName: custName, mtm: mtm, availableCash: availableCash));
} else if (positions[index] == false) {
selectedContacts.removeWhere(
(element) => element.custID == pos[index].custID);
}}); }, );});}
}

type 'int' is not a subtype of type 'String' - Flutter Android

My app was working fine yesterday and it was displaying the posts on Timeline page correctly. But now today when I opened by project again and wanted to continue working on it, when I run the Debug app, it generated an error on the Timeline page that "type int is not a subtype of type String".
Here is my Timeline.dart file:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttershare/models/user.dart';
import 'package:fluttershare/pages/home.dart';
import 'package:fluttershare/pages/search.dart';
import 'package:fluttershare/widgets/header.dart';
import 'package:fluttershare/widgets/post.dart';
import 'package:fluttershare/widgets/progress.dart';
class Timeline extends StatefulWidget {
final User currentUser;
Timeline({this.currentUser});
#override
_TimelineState createState() => _TimelineState();
}
class _TimelineState extends State<Timeline> {
List<Post> posts;
List<String> followingList = [];
// #override
// void initState() {
// super.initState();
// getTimeline().whenComplete(() {
// setState(() {});
// });
// getFollowing();
// }
Future<void> getTimeline() async {
QuerySnapshot snapshot = await timelineRef
.document(widget.currentUser.id)
.collection('timelinePosts')
.orderBy('timestamp', descending: true)
.getDocuments();
List<Post> posts =
snapshot.documents.map((doc) => Post.fromDocument(doc)).toList();
setState(() {
this.posts = posts;
});
}
getFollowing() async {
QuerySnapshot snapshot = await followingRef
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState(() {
followingList = snapshot.documents.map((doc) => doc.documentID).toList();
});
}
buildTimeline() {
if (posts == null) {
return circularProgress();
} else if (posts.isEmpty) {
return buildUsersToFollow();
} else {
return ListView.builder(
itemCount: posts.length,
itemBuilder: (BuildContext ctxt, int index) {
return Text(posts[index].toString());
});
}
}
buildUsersToFollow() {
return StreamBuilder(
stream:
usersRef.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
List<UserResult> userResults = [];
snapshot.data.documents.forEach((doc) {
User user = User.fromDocument(doc);
final bool isAuthUser = currentUser.id == user.id;
final bool isFollowingUser = followingList.contains(user.id);
if (isAuthUser) {
return;
} else if (isFollowingUser) {
return;
} else {
UserResult userResult = UserResult(user);
userResults.add(userResult);
}
});
return Container(
color: Theme.of(context).accentColor.withOpacity(0.2),
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.person_add,
color: Theme.of(context).primaryColor,
size: 30.0,
),
SizedBox(
width: 8.0,
),
Text(
"Users to Follow",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 30.0,
),
),
],
),
),
Column(children: userResults),
],
),
);
},
);
}
#override
Widget build(context) {
return Scaffold(
appBar: header(context, isAppTitle: true),
body: RefreshIndicator(
onRefresh: () => getTimeline(),
child: FutureBuilder(
future: timelineRef
.document(widget.currentUser.id)
.collection('timelinePosts')
// .orderBy('timestamp', descending: true)
.getDocuments(),
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.connectionState != ConnectionState.waiting) {
print("${widget.currentUser.id}");
print("${snapshot.data.documents.length}");
var posts = snapshot.data.documents
.map((doc) => Post.fromDocument(doc))
.toList();
if (posts.length > 0)
return ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
// posts[index] gives you the post item.
return posts[index];
});
// else
// return
} else
return CircularProgressIndicator();
})),
);
}
}
Debug Console:
In
setState(() {
followingList = snapshot.documents.map((doc) => doc.documentID).toList();
});
Do This
setState(() {
followingList = snapshot.documents.map((doc) => doc.documentID).toList().toString();
});

Timeline Posts are not being displayed

My timeline page is not displaying any posts of users which I'm following. The posts are working fine on the user's profile page but not showing up on timeline. Here is the code of my timeline, and I don't see any debug errors too, so how to identify what's wrong here? Did I miss something? However, for the new user sign up, it does show users to follow on the timeline page.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttershare/models/user.dart';
import 'package:fluttershare/pages/home.dart';
import 'package:fluttershare/pages/search.dart';
import 'package:fluttershare/widgets/header.dart';
import 'package:fluttershare/widgets/post.dart';
import 'package:fluttershare/widgets/progress.dart';
class Timeline extends StatefulWidget {
final User currentUser;
Timeline({this.currentUser});
#override
_TimelineState createState() => _TimelineState();
}
class _TimelineState extends State<Timeline> {
List<Post> posts;
List<String> followingList = [];
#override
void initState() {
super.initState();
getTimeline();
getFollowing();
}
getTimeline() async {
QuerySnapshot snapshot = await timelineRef
.document(widget.currentUser.id)
.collection('timelinePosts')
.orderBy('timestamp', descending: true)
.getDocuments();
List<Post> posts =
snapshot.documents.map((doc) => Post.fromDocument(doc)).toList();
setState(() {
this.posts = posts;
});
}
getFollowing() async {
QuerySnapshot snapshot = await followingRef
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState(() {
followingList = snapshot.documents.map((doc) => doc.documentID).toList();
});
}
buildTimeline() {
if (posts == null) {
return circularProgress();
} else if (posts.isEmpty) {
return buildUsersToFollow();
} else {
return ListView(children: posts);
}
}
buildUsersToFollow() {
return StreamBuilder(
stream:
usersRef.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
List<UserResult> userResults = [];
snapshot.data.documents.forEach((doc) {
User user = User.fromDocument(doc);
final bool isAuthUser = currentUser.id == user.id;
final bool isFollowingUser = followingList.contains(user.id);
if (isAuthUser) {
return;
} else if (isFollowingUser) {
return;
} else {
UserResult userResult = UserResult(user);
userResults.add(userResult);
}
});
return Container(
color: Theme.of(context).accentColor.withOpacity(0.2),
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.person_add,
color: Theme.of(context).primaryColor,
size: 30.0,
),
SizedBox(
width: 8.0,
),
Text(
"Users to Follow",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 30.0,
),
),
],
),
),
Column(children: userResults),
],
),
);
},
);
}
#override
Widget build(context) {
return Scaffold(
appBar: header(context, isAppTitle: true),
body: RefreshIndicator(
onRefresh: () => getTimeline(),
child: buildTimeline(),
),
);
}
}
Update your code
buildTimeline() {
if (posts == null) {
return circularProgress();
} else if (posts.isEmpty) {
return buildUsersToFollow();
} else {
return ListView.builder(
itemCount: posts.length,
itemBuilder: (BuildContext ctxt, int index) {
return Text(posts[index].toString);
});
}
}
ListView takes Widgets as a children. posts is not a widgets of any kind.

Flutter StreamBuilder with Firestore Pagination

I'm trying to build a basic chat feature where all of a users chat messages are stored as documents in a "chats" collection. I have successfully implemented pagination to ensure I am not overpulling data until the user scrolls.
However, even though I have a StreamBuilder, new chat documents are not appearing automatically like they normally would. Why is the streambuilder not registering and displaying these new messages?
Here is my code:
class MotivatorChat extends StatefulWidget {
#override
_MotivatorChatState createState() => _MotivatorChatState();
}
class _MotivatorChatState extends State<MotivatorChat> {
Firestore firestore = Firestore.instance;
List<DocumentSnapshot> chats = [];
bool isLoading = false;
bool hasMore = true;
int documentLimit = 10;
DocumentSnapshot lastDocument;
ScrollController _scrollController = ScrollController();
StreamController<List<DocumentSnapshot>> _controller = StreamController<List<DocumentSnapshot>>();
Stream<List<DocumentSnapshot>> get _streamController => _controller.stream;
#override
void initState() {
super.initState();
getChats();
_scrollController.addListener(() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.20;
if (maxScroll - currentScroll <= delta) {
getChats();
}
});
}
getChats() async {
if (!hasMore) {
print('No More Chats');
return;
}
if (isLoading) {
return;
}
setState(() {
isLoading = true;
});
QuerySnapshot querySnapshot;
if (lastDocument == null) {
querySnapshot = await firestore
.collection('chats')
.orderBy('timestamp', descending: true)
.limit(documentLimit)
.getDocuments();
} else {
querySnapshot = await firestore
.collection('chats')
.orderBy('timestamp', descending: true)
.startAfterDocument(lastDocument)
.limit(documentLimit)
.getDocuments();
print(1);
}
if (querySnapshot.documents.length < documentLimit) {
hasMore = false;
}
lastDocument = querySnapshot.documents[querySnapshot.documents.length - 1];
chats.addAll(querySnapshot.documents);
_controller.sink.add(chats);
setState(() {
isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Pagination with Firestore'),
),
body: Column(children: [
Expanded(
child: StreamBuilder<List<DocumentSnapshot>>(
stream: _streamController,
builder: (sContext, snapshot) {
print(snapshot.connectionState);
if (snapshot.hasData && snapshot.data.length > 0) {
return ListView.builder(
reverse: true,
controller: _scrollController,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(top: 20),
child: Container(
height: 20,
child: Text(snapshot.data[index].data['text']),
),
);
},
);
} else {
return Center(
child: Text('No Data...'),
);
}
},
),
),
isLoading
? Container(
width: MediaQuery
.of(context)
.size
.width,
padding: EdgeInsets.all(5),
color: Colors.yellowAccent,
child: Text(
'Loading',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
)
: Container(),
]),
);
}
}
Updated StreamBuilder
StreamBuilder<List<DocumentSnapshot>>(
stream: _streamController,
builder: (sContext, snapshot) {
if (snapshot.connectionState == ConnectionState.none) {
return Text("None");
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
} else if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData && snapshot.data.length > 0) {
return ListView.builder(
reverse: true,
controller: _scrollController,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(top: 20),
child: Container(
height: 20,
child: Text(snapshot.data[index].data['text']),
),
);
},
);
} else {
return Center(
child: Text('No Data...'),
);
}
} else {
return Text("return list");
}
},
),
I try your code and set document limit to 20, it work fine.
Example on DartPad
If hasMore is false, the stream will not sink new data.
don't check hasMore
// if (!hasMore) {
// print('No More Chats');
// return;
// }
and check documents
// if (querySnapshot.documents.length < documentLimit) {
// hasMore = false;
// }
if (querySnapshot.documents.isEmpty) {
print('No More Chats');
setLoading(false);
return;
}
I test on DartPad, It sends data every 3 seconds.
See if this code is helpful:
class _MessagesState extends State<Messages> {
ScrollController _scrollController = ScrollController();
#override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.offset >=
(_scrollController.position.maxScrollExtent) &&
!_scrollController.position.outOfRange) {
_getChats();
}
});
}
final StreamController<List<DocumentSnapshot>> _chatController =
StreamController<List<DocumentSnapshot>>.broadcast();
List<List<DocumentSnapshot>> _allPagedResults = [<DocumentSnapshot>[]];
static const int chatLimit = 10;
DocumentSnapshot? _lastDocument;
bool _hasMoreData = true;
Stream<List<DocumentSnapshot>> listenToChatsRealTime() {
_getChats();
return _chatController.stream;
}
void _getChats() {
final CollectionReference _chatCollectionReference = FirebaseFirestore
.instance
.collection("ChatRoom")
.doc(widget.chatRoomId)
.collection("channel");
var pagechatQuery = _chatCollectionReference
.orderBy('createdAt', descending: true)
.limit(chatLimit);
if (_lastDocument != null) {
pagechatQuery = pagechatQuery.startAfterDocument(_lastDocument!);
}
if (!_hasMoreData) return;
var currentRequestIndex = _allPagedResults.length;
pagechatQuery.snapshots().listen(
(snapshot) {
if (snapshot.docs.isNotEmpty) {
var generalChats = snapshot.docs.toList();
var pageExists = currentRequestIndex < _allPagedResults.length;
if (pageExists) {
_allPagedResults[currentRequestIndex] = generalChats;
} else {
_allPagedResults.add(generalChats);
}
var allChats = _allPagedResults.fold<List<DocumentSnapshot>>(
<DocumentSnapshot>[],
(initialValue, pageItems) => initialValue..addAll(pageItems));
_chatController.add(allChats);
if (currentRequestIndex == _allPagedResults.length - 1) {
_lastDocument = snapshot.docs.last;
}
_hasMoreData = generalChats.length == chatLimit;
}
},
);
}
#override
Widget build(BuildContext context) {
return Container(
child: StreamBuilder<List<DocumentSnapshot>>(
stream: listenToChatsRealTime(),
builder: (ctx, chatSnapshot) {
if (chatSnapshot.connectionState == ConnectionState.waiting ||
chatSnapshot.connectionState == ConnectionState.none) {
return chatSnapshot.hasData
? Center(
child: CircularProgressIndicator(),
)
: Center(
child: Text("Start a conversation."),
);
} else {
if (chatSnapshot.hasData) {
final chatDocs = chatSnapshot.data!;
final user = Provider.of<User?>(context);
return ListView.builder(
controller: _scrollController,
reverse: true,
itemBuilder: (ctx, i) {
Map chatData = chatDocs[i].data() as Map;
return MessageBubble(
username: chatData['username'],
message: chatData['text'],
isMe: chatData['senderId'] == user!.uid,
key: ValueKey(chatDocs[i].id));
},
itemCount: chatDocs.length,
);
} else {
return CircularProgressIndicator();
}
}
}),
);
}
}
I referred to this answer: Pagination in Flutter with Firebase Realtime Database

Flutter load limited(20 documents) records and display in list view at a time

I have a requirement to read only 20 records at a time from Firestore and display in list view. When user click next button then I need to load next 20 documents. It is similar to paging.
Can some one help on how to do this. Any library available for this?
The below code limits the number of records to 3, it will load more records while scrolling the list instead of load more button starting from the last document retrieved from the cloud store
class Feed extends StatefulWidget {
Feed({this.firestore});
final Firestore firestore;
#override
_FeedState createState() => _FeedState();
}
class _FeedState extends State<Feed> {
ScrollController controller;
DocumentSnapshot _lastVisible;
bool _isLoading;
CollectionReference get homeFeeds => widget.firestore.collection('homefeed');
List<DocumentSnapshot> _data = new List<DocumentSnapshot>();
final scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
controller = new ScrollController()..addListener(_scrollListener);
super.initState();
_isLoading = true;
_getData();
}
Future<Null> _getData() async {
// await new Future.delayed(new Duration(seconds: 5));
QuerySnapshot data;
if (_lastVisible == null)
data = await widget.firestore
.collection('homefeed')
.orderBy('created_at', descending: true)
.limit(3)
.getDocuments();
else
data = await widget.firestore
.collection('homefeed')
.orderBy('created_at', descending: true)
.startAfter([_lastVisible['created_at']])
.limit(3)
.getDocuments();
if (data != null && data.documents.length > 0) {
_lastVisible = data.documents[data.documents.length - 1];
if (mounted) {
setState(() {
_isLoading = false;
_data.addAll(data.documents);
});
}
} else {
setState(() => _isLoading = false);
scaffoldKey.currentState?.showSnackBar(
SnackBar(
content: Text('No more posts!'),
),
);
}
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: new AppBar(),
body: RefreshIndicator(
child: ListView.builder(
controller: controller,
itemCount: _data.length + 1,
itemBuilder: (_, int index) {
if (index < _data.length) {
final DocumentSnapshot document = _data[index];
return new Container(
height: 200.0,
child: new Text(document['question']),
);
}
return Center(
child: new Opacity(
opacity: _isLoading ? 1.0 : 0.0,
child: new SizedBox(
width: 32.0,
height: 32.0,
child: new CircularProgressIndicator()),
),
);
},
),
onRefresh: ()async{
_data.clear();
_lastVisible=null;
await _getData();
},
),
);
}
#override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
void _scrollListener() {
if (!_isLoading) {
if (controller.position.pixels == controller.position.maxScrollExtent) {
setState(() => _isLoading = true);
_getData();
}
}
}
}
hope it helps