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

标签 flutter dart

我正在尝试在 flutter 中构建一个 ListView ,它根据索引和每页记录加载数据库

我能够显示固定数量的记录但需要一些帮助如何获取和显示下一组记录等等

这是我的代码片段

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),
                  ],
                ),
              ));
        });
  }

因此,它会加载第一个带有 n 条记录的页面,但我不知道当您使用 future builder 到达当前记录的底部时如何加载下一组页面。

谢谢你的帮助

最佳答案

如果您希望显示无限列表,则不会 StreamBuilder会更好?您是否有需要专门使用 FutureBuilder 的特定用例?这是一个简单的演示,它使用 Firestore 提供数据,并使用 ListView.builder 进行分页。

此示例实现了来自 Firebase 官方文档的片段 Firestore pagination .

在这个演示中,有两种方法可以将数据加载到 View 上。

  • 刷新整个 ListView 使用 RefreshIndicator
  • 向下滚动到列表底部以加载 ListView 中的下一个文档。 ScrollController 用于确定用户是否点击了列表的底部。
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())));
        });
      });
    });
  }
}

要解析文档中的数据,您可以为您的对象创建一个模型。

class DocObj {
  var documentName;

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

  dynamic getDocName() => documentName;

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

示例处理来自 Firestore 的数据。

firestore dashboard

这是应用程序运行时的样子。

demo

关于 flutter :How to build a infinite list using future builder that display n-record at a time,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56677121/

相关文章:

flutter - 如何访问Firestore中的嵌套项目?

image - 失败时重新加载缓存的网络图像

ios - Xcode 构建失败, fatal error : module 'firebase_auth' not found @import firebase_auth;

android - Flutter 插件 list 占位符错误

android - Flutter Navigator Pop 不起作用

使用网格系统的 Flutter 布局

dart - 没有镜像包的flutter中如何使用ByteData和ByteBuffer

flutter - 如何在 flutter 中初始化 WebView Controller

dart - 使用 browser_client.dart 进行多部分请求

dart - 如何使用android studio在flutter上加载图像