Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter :How to build a infinite list using future builder that display n-record at a time

Tags:

flutter

dart

I am trying to build a list view in flutter that load data base on index and record per page

I am able to display a fix number of record but need some help how get and display the next set of record and so on

Here is my code snippet

Widget build(BuildContext context) {
    return SafeArea(
        child: Column(
      children: <Widget>[
        searchBoxWidget(),
        Expanded(
          child: FutureBuilder(
            future: getRecordToDisplay(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                case ConnectionState.active:
                case ConnectionState.waiting:
                  return Center(child: CircularProgressIndicator());
                case ConnectionState.done:
                  if (snapshot.hasError) {
                    return Text('You have some error : ');
                  } else if (snapshot.data != null) {
                    return buildListView(snapshot);
                  } else {
                    return Text('You have some error : ');
                  }
              }
            },
          ),
        ),
      ],
    ));
  }


void initState() {
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {}
    });
  }




 Future<Jobs> getRecordToDisplay() async {
    return await getJobs(startPage, recordPerFetch);
  }


 ListView buildListView(AsyncSnapshot snapshot) {
    return ListView.builder(
        itemCount: snapshot.data.hits.length,
        controller: _scrollController,
        itemBuilder: (BuildContext context, int index) {
          return InkWell(
              onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => DetailPage(
                        lobId: snapshot.data.hits[index].lobId,
                        atsReference: snapshot.data.hits[index].atsReference),
                  ),
                );
              },
              child: Container(
                // width: MediaQuery.of(context).size.width,
                padding: const EdgeInsets.all(14.0),

                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Flexible(
                          child: Padding(
                            padding:
                                const EdgeInsets.only(top: 8.0, bottom: 8.0),
                            child: Text(
                              snapshot.data.hits[index].title,
                              style: TextStyle(
                                color: Color(0xff2175D9),
                                fontSize: 18.0,
                              ),
                            ),
                          ),
                        ),
                        Icon(
                          Icons.arrow_forward,
                          color: Colors.blue,
                        )
                      ],
                    ),
                    Text(
                      snapshot.data.hits[index].jobLocation.city +
                          " , " +
                          snapshot
                              .data.hits[index].jobLocation.stateAbbreviation,
                      style: TextStyle(
                        color: Color(0xff0f1941),
                        fontSize: 16.0,
                      ),
                    ),
                    SizedBox(
                      height: 8.0,
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          snapshot.data.hits[index].salary.salaryString,
                          style: TextStyle(
                            color: Color(0xff0f1941),
                            fontSize: 16.0,
                          ),
                        ),
                        Text(
                          snapshot.data.hits[index].createdDate,
                          style: TextStyle(
                            color: Color(0xff0f1941),
                            fontSize: 14.0,
                          ),
                        ),
                      ],
                    ),
                    SizedBox(
                      height: 8.0,
                    ),
                    Divider(color: Colors.brown),
                  ],
                ),
              ));
        });
  }

So, it loads the first with n record but I don't know how to load the next set of pages when you reach the bottom of the current record with a future builder.

Thanks for your help

like image 529
user2570135 Avatar asked Jan 17 '26 07:01

user2570135


1 Answers

If you're expecting an infinite list to be displayed, won't StreamBuilder be better? Do you have a particular use case for the need to use FutureBuilder specifically? Here's a simple demo that uses Firestore to provide data, and ListView.builder with pagination.

This sample implements snippets from Firebase official doc for Firestore pagination.

There are two ways to load the data on the view in this demo.

  • Refresh the entire ListView using RefreshIndicator
  • Scroll down to hit the bottom of the list to load up the next documents in the ListView. ScrollController is used to determine if the user has hit the bottom part of the list.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

import 'DocObj.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // Initialize Firebase
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    getDocuments();
    scrollController.addListener(() {
      if (scrollController.position.atEdge) {
        if (scrollController.position.pixels == 0)
          print('ListView scroll at top');
        else {
          print('ListView scroll at bottom');
          getDocumentsNext(); // Load next documents
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: listDocument.length != 0
            ? RefreshIndicator(
                child: ListView.builder(
                  physics: AlwaysScrollableScrollPhysics(),
                  controller: scrollController,
                  itemCount: listDocument.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text('${listDocument[index].documentName}'),
                    );
                  },
                ),
                onRefresh: getDocuments, // Refresh entire list
              )
            : CircularProgressIndicator(),
      ),
    );
  }

  List<DocObj> listDocument;
  QuerySnapshot collectionState;
  // Fetch first 15 documents
  Future<void> getDocuments() async {
    listDocument = List();
    var collection = FirebaseFirestore.instance
        .collection('sample_pagination')
        .orderBy("name")
        .limit(15);
    print('getDocuments');
    fetchDocuments(collection);
  }

  // Fetch next 5 documents starting from the last document fetched earlier
  Future<void> getDocumentsNext() async {
    // Get the last visible document
    var lastVisible = collectionState.docs[collectionState.docs.length-1];
    print('listDocument legnth: ${collectionState.size} last: $lastVisible');

    var collection = FirebaseFirestore.instance
        .collection('sample_pagination')
        .orderBy("name").startAfterDocument(lastVisible).limit(5);

    fetchDocuments(collection);
  }

  fetchDocuments(Query collection){
    collection.get().then((value) {
      collectionState = value; // store collection state to set where to start next
      value.docs.forEach((element) {
        print('getDocuments ${element.data()}');
        setState(() {
          listDocument.add(DocObj(DocObj.setDocDetails(element.data())));
        });
      });
    });
  }
}

To parse the data inside the document, you can create a model for your object.

class DocObj {
  var documentName;

  DocObj(DocObj doc) {
    this.documentName = doc.getDocName();
  }

  dynamic getDocName() => documentName;

  DocObj.setDocDetails(Map<dynamic, dynamic> doc)
      : documentName = doc['name'];
}

The sample handles this data from Firestore.

firestore dashboard

Here's how the app looks when running.

demo

like image 98
Omatt Avatar answered Jan 20 '26 05:01

Omatt