How to get an infinite scroll with ListView from Firestore with Flutter

3,530

Ok, after looking on the net I found a way to resolve this issue thanks to this link

I write here the complete code if someone needs:

    class AudioScreenList extends StatefulWidget {
  @override
  _AudioScreenListState createState() => _AudioScreenListState();
}

class _AudioScreenListState extends State<AudioScreenList> {
  bool isPerformingRequest = false;

  static const String _collectionRussian = 'speech-ru';
  static const String _loadingTextRussian = 'Loading...';
  static const String _speechTitle = 'speechTitle';
  static const String _speechSubtitle = 'speechSubtitle';
  static const String _audioLink = 'audioLink';
  static const String _pastorCode = 'pastorCode';
  static const String _pastorName = 'pastorName';
  static const String _id = "id";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: StreamBuilder(
            stream: Firestore.instance
                .collection(_collectionRussian)
                .orderBy(_id, descending: true)
                .snapshots(),
            builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
              if (!snapshot.hasData)
                return const Center(
                    child: Text(
                  _loadingTextRussian,
                  style: TextStyle(fontSize: 25.0, color: Colors.grey),
                ));
              return ListView(children: getExpenseItems(snapshot));
            }));
  }

  getExpenseItems(AsyncSnapshot<QuerySnapshot> snapshot) {
    return snapshot.data.documents
        .map((doc) => new Container(
            margin: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
            child: ListTile(
                leading: Padding(
                    padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
                    child: Hero(
                        tag: doc[_audioLink],
                        child: new ClipOval(
                            child: Container(
                          width: 70.0,
                          height: 70.0,
                          child: Image.asset(
                            Utils.getImagePastor(doc[_pastorCode]),
                            fit: BoxFit.cover,
                          ),
                        )))),
                title: new Text(doc[_speechTitle]),
                subtitle: new Text(doc[_speechSubtitle].toString() +
                    " - " +
                    doc[_pastorName].toString()),
                onTap: () => onPressed(context, doc[_speechTitle],
                    doc[_pastorCode], doc[_audioLink]))))
        .toList();
  }

  onPressed(BuildContext context, String speechTitle, String pastorCode,
      String audioLink) {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) =>
                ScreenAudioSelected(speechTitle, pastorCode, audioLink)));
  }
}
Share:
3,530
Singorenko
Author by

Singorenko

Updated on December 09, 2022

Comments

  • Singorenko
    Singorenko over 1 year

    I'm working with Firestore and ListView in Flutter. Every works fine for some items in the list, but I scroll down farther than the seen limits, I got many messages: "the method was called on null". Seems that the ListView.builder is not handling correctly all the date request from the Firebase or something like it.

    This is the code:

    import 'package:flutter/material.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:father_home_flutter/screen_audio_selected.dart';
    import 'package:father_home_flutter/model/utils.dart';
    
    class AudioScreenList extends StatelessWidget {
      static const String _collectionRussian = 'speech-ru';
      static const String _loadingTextRussian = 'Loading...';
      static const String _speechTitle = 'speechTitle';
      static const String _speechSubtitle = 'speechSubtitle';
      static const String _audioLink = 'audioLink';
      static const String _pastorCode = 'pastorCode';
      static const String _pastorName = 'pastorName';
      static const String _id = "id";
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: StreamBuilder(
                stream: Firestore.instance
                    .collection(_collectionRussian)
                    .limit(100)
                    .orderBy(_id, descending: true)
                    .snapshots(),
                builder: (context, snapshot) {
                  if (!snapshot.hasData)
                    return const Center(
                        child: Text(
                      _loadingTextRussian,
                      style: TextStyle(fontSize: 25.0, color: Colors.grey),
                    ));
                  return ListView.builder(
                    itemCount: snapshot.data.documents.length,
                    itemBuilder: (BuildContext context, int i) =>
                        _buildRow(context, snapshot.data.documents[i]),
                  );
                }));
      }
    
      Widget _buildRow(BuildContext context, DocumentSnapshot document) {
        return Container(
            margin: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
            height: 90.0,
            child: ListTile(
                leading: Padding(
                    padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
                    child: Hero(
                        tag: document[_audioLink],
                        child: new ClipOval(
                            child: Container(
                          width: 70.0,
                          height: 70.0,
                          child: Image.asset(
                            Utils.getImagePastor(document[_pastorCode]),
                            fit: BoxFit.cover,
                          ),
                        )))),
                title: Text(document[_speechTitle]),
                subtitle:
                    Text(document[_speechSubtitle] + " - " + document[_pastorName]),
                onTap: () => onPressed(context, document[_speechTitle],
                    document[_pastorCode], document[_audioLink])));
      }
    
      onPressed(BuildContext context, String speechTitle, String pastorCode,
          String audioLink) {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) =>
                    ScreenAudioSelected(speechTitle, pastorCode, audioLink)));
      }
    }
    

    and this is the problem on the simulator:

    enter image description here

    I was looking around the web for ways how to handle it, but I just found examples where simulate the server request like this example https://flutter-academy.com/flutter-listview-infinite-scrolling/

    Anyone had face the same problem or has an idea about how to solve it?.