FirestoreListView<Document> constructor

FirestoreListView<Document>({
  1. Key? key,
  2. required Query<Document> query,
  3. required FirestoreItemBuilder<Document> itemBuilder,
  4. int pageSize = 10,
  5. FirestoreLoadingBuilder? loadingBuilder,
  6. FirestoreErrorBuilder? errorBuilder,
  7. Axis scrollDirection = Axis.vertical,
  8. bool reverse = false,
  9. ScrollController? controller,
  10. bool? primary,
  11. ScrollPhysics? physics,
  12. bool shrinkWrap = false,
  13. EdgeInsetsGeometry? padding,
  14. double? itemExtent,
  15. Widget? prototypeItem,
  16. bool addAutomaticKeepAlives = true,
  17. bool addRepaintBoundaries = true,
  18. bool addSemanticIndexes = true,
  19. double? cacheExtent,
  20. int? semanticChildCount,
  21. DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  22. ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
  23. String? restorationId,
  24. Clip clipBehavior = Clip.hardEdge,
})

A ListView.builder that obtains its items from a Firestore query.

As an example, consider the following collection:

class Movie {
  Movie({required this.title, required this.genre});

  Movie.fromJson(Map<String, Object?> json)
    : this(
        title: json['title']! as String,
        genre: json['genre']! as String,
      );

  final String title;
  final String genre;

  Map<String, Object?> toJson() {
    return {
      'title': title,
      'genre': genre,
    };
  }
}

final moviesCollection = FirebaseFirestore.instance.collection('movies').withConverter<Movie>(
     fromFirestore: (snapshot, _) => Movie.fromJson(snapshot.data()!),
     toFirestore: (movie, _) => movie.toJson(),
   );

Using FirestoreListView, we can now show the list of movies by writing:

FirestoreListView<Movie>(
  query: moviesCollection.orderBy('title'),
  itemBuilder: (context, snapshot) {
    Movie movie = snapshot.data();
    return Text(movie.title);
  },
)

For advanced UI use-cases, consider switching to FirestoreQueryBuilder.

Implementation

FirestoreListView({
  Key? key,
  required Query<Document> query,
  required FirestoreItemBuilder<Document> itemBuilder,
  int pageSize = 10,
  FirestoreLoadingBuilder? loadingBuilder,
  FirestoreErrorBuilder? errorBuilder,
  Axis scrollDirection = Axis.vertical,
  bool reverse = false,
  ScrollController? controller,
  bool? primary,
  ScrollPhysics? physics,
  bool shrinkWrap = false,
  EdgeInsetsGeometry? padding,
  double? itemExtent,
  Widget? prototypeItem,
  bool addAutomaticKeepAlives = true,
  bool addRepaintBoundaries = true,
  bool addSemanticIndexes = true,
  double? cacheExtent,
  int? semanticChildCount,
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior =
      ScrollViewKeyboardDismissBehavior.manual,
  String? restorationId,
  Clip clipBehavior = Clip.hardEdge,
}) : super(
        key: key,
        query: query,
        pageSize: pageSize,
        builder: (context, snapshot, _) {
          if (snapshot.isFetching) {
            return loadingBuilder?.call(context) ??
                const Center(child: CircularProgressIndicator());
          }

          if (snapshot.hasError && errorBuilder != null) {
            return errorBuilder(
              context,
              snapshot.error!,
              snapshot.stackTrace!,
            );
          }

          return ListView.builder(
            itemCount: snapshot.docs.length,
            itemBuilder: (context, index) {
              final isLastItem = index + 1 == snapshot.docs.length;
              if (isLastItem && snapshot.hasMore) snapshot.fetchMore();

              final doc = snapshot.docs[index];
              return itemBuilder(context, doc);
            },
            scrollDirection: scrollDirection,
            reverse: reverse,
            controller: controller,
            primary: primary,
            physics: physics,
            shrinkWrap: shrinkWrap,
            padding: padding,
            itemExtent: itemExtent,
            prototypeItem: prototypeItem,
            addAutomaticKeepAlives: addAutomaticKeepAlives,
            addRepaintBoundaries: addRepaintBoundaries,
            addSemanticIndexes: addSemanticIndexes,
            cacheExtent: cacheExtent,
            semanticChildCount: semanticChildCount,
            dragStartBehavior: dragStartBehavior,
            keyboardDismissBehavior: keyboardDismissBehavior,
            restorationId: restorationId,
            clipBehavior: clipBehavior,
          );
        },
      );