Take a try with below code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | class ProductList extends StatefulWidget { @override _ProductListState createState() => _ProductListState(); } class _ProductListState extends State<ProductList> { StreamController<List<DocumentSnapshot>> _streamController = StreamController<List<DocumentSnapshot>>(); List<DocumentSnapshot> _products = []; bool _isRequesting = false; bool _isFinish = false; void onChangeData(List<DocumentChange> documentChanges) { var isChange = false; documentChanges.forEach((productChange) { if (productChange.type == DocumentChangeType.removed) { _products.removeWhere((product) { return productChange.document.documentID == product.documentID; }); isChange = true; } else { if (productChange.type == DocumentChangeType.modified) { int indexWhere = _products.indexWhere((product) { return productChange.document.documentID == product.documentID; }); if (indexWhere >= 0) { _products[indexWhere] = productChange.document; } isChange = true; } } }); if(isChange) { _streamController.add(_products); } } @override void initState() { Firestore.instance .collection('products') .snapshots() .listen((data) => onChangeData(data.documentChanges)); requestNextPage(); super.initState(); } @override void dispose() { _streamController.close(); super.dispose(); } @override Widget build(BuildContext context) { return NotificationListener<ScrollNotification>( onNotification: (ScrollNotification scrollInfo) { if (scrollInfo.metrics.maxScrollExtent == scrollInfo.metrics.pixels) { requestNextPage(); } return true; }, child: StreamBuilder<List<DocumentSnapshot>>( stream: _streamController.stream, builder: (BuildContext context, AsyncSnapshot<List<DocumentSnapshot>> snapshot) { if (snapshot.hasError) return new Text('Error: ${snapshot.error}'); switch (snapshot.connectionState) { case ConnectionState.waiting: return new Text('Loading...'); default: log("Items: " + snapshot.data.length.toString()); return ListView.separated( separatorBuilder: (context, index) => Divider( color: Colors.black, ), itemCount: snapshot.data.length, itemBuilder: (context, index) => Padding( padding: const EdgeInsets.symmetric(vertical: 32), child: new ListTile( title: new Text(snapshot.data[index]['name']), subtitle: new Text(snapshot.data[index]['description']), ), ), ); } }, )); } void requestNextPage() async { if (!_isRequesting && !_isFinish) { QuerySnapshot querySnapshot; _isRequesting = true; if (_products.isEmpty) { querySnapshot = await Firestore.instance .collection('products') .orderBy('index') .limit(5) .getDocuments(); } else { querySnapshot = await Firestore.instance .collection('products') .orderBy('index') .startAfterDocument(_products[_products.length - 1]) .limit(5) .getDocuments(); } if (querySnapshot != null) { int oldSize = _products.length; _products.addAll(querySnapshot.documents); int newSize = _products.length; if (oldSize != newSize) { _streamController.add(_products); } else { _isFinish = true; } } _isRequesting = false; } } } |
If you like this question & answer and want to contribute, then write your question & answer and email to freewebmentor[@]gmail.com. Your question and answer will appear on FreeWebMentor.com and help other developers.