如何在列表视图的滚动中添加更多项目?

Posted

技术标签:

【中文标题】如何在列表视图的滚动中添加更多项目?【英文标题】:How do i add more items on scroll in the listview? 【发布时间】:2020-08-03 18:09:57 【问题描述】:

此代码当前加载存储在 Firestore 集合中的所有 brews。我如何才能加载最初仅 10 个 brews,然后当用户向下滚动并到达 10 个 brews 列表的末尾时。它应该在最后一次 brew 之后再加载 10 个。并且 brews 应该根据时间戳进行排序。

class BrewList extends StatefulWidget 
  @override
  _BrewListState createState() => _BrewListState();


class _BrewListState extends State<BrewList> 
  List<Brew> brews = [];
   ScrollController _controller = ScrollController();

  @override
  void initState() 
    _startFirst();
    super.initState();
    _controller.addListener(_scrollListener);
  

       _scrollListener() 
    setState(() 
      if (_controller.position.atEdge) 
        if (_controller.position.pixels == 0) 


         else 



        
      
    );
  



 _startFirst() async 
    brews = await DatabaseService().brews ?? [];
    setState(() 
      brews = brews;

    );
  

  @override
  Widget build(BuildContext context) 
    Future<void> _refreshBrews() async 
      List<Brew> tempList = await DatabaseService().brews;
      setState(() 
        brews = tempList;
      );
      print(brews);
    


    return RefreshIndicator(
      onRefresh: _refreshBrews,
      child: ListView.builder(
        controller: _controller,
        itemCount: brews.length,
        itemBuilder: (context, index) 
          return BrewTile(brew: brews[index]);
        ,
      ),
    );
  



Future<List<Brew>> get brewss async 
    QuerySnapshot snapshot = await brewsCollection
        .orderBy('timestamp', descending: true)
          .limit(2)
        .getDocuments();

    return _postListFromSnapshot(snapshot);
  

【问题讨论】:

首先您只想获取 10 个项目? 它可能是 20..但是我想在滚动上加载更多.. ***.com/a/60315739/2252830 非常感谢..但是你能不能把它简化一下..我只是这里的初学者,这看起来有点复杂..@pskink 你有一个完整的工作小部件,只需使用它 【参考方案1】:

您可以使用滚动控制器和侦听器来确定用户是否已滚动到屏幕底部。如果他们已经从数据库服务加载接下来的 10 个项目。

这看起来像下面这样。

ScrollController _controller = ScrollController(); 

@override
void initState() 
  super.initState();
  // add listener
  _controller.addListener(_scrollListener);


_scrollListener() 
  setState(() 
    if (_controller.position.atEdge) 
      if (_controller.position.pixels == 0)
      
        // user is at top of the list
      
      else 
      
        // user is at the bottom of the list.
        // load next 10 items and add them to the list of items in the list.
       
    
 );

【讨论】:

Future> 获取 brews async QuerySnapshot 快照 = await brewsCollection .orderBy('timestamp', descending: true).getDocuments();返回 _brewListFromSnapshot(快照); 这就是我获取当前列表的方式..我已经添加了 scrollController ..你可以告诉我我需要在这里添加的功能吗? 你的意思是如何一次从 Firestore 中获取 10 个项目? 最初使用上面的代码..它会加载列表中的所有 brews..但我最初只想加载 10 个 brews,然后当用户到达最初加载的 10 个 brews 列表的末尾时..我想再加载10个等等.. 这与如何使用某种查询对存储在 Firestore 中的数据进行分页有关。我看到你之前已经问过这个问题并得到了合理的回答。 ***.com/a/61133438/5211220 基本上,您需要能够编写查询以获取 10 个块的文档。如果您在文档上有一个自动递增的整数属性,您可以按该属性排序,然后最初选择该属性在 0 和 11 之间的位置.然后在 10 到 21 等之间的第二个查询。【参考方案2】:

不确定以下是否会有所帮助,但这是我在我的颤振应用程序中所做的。特别注意底部的_onScroll函数。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../blocs/feed_bloc/feed_events.dart';
import '../../blocs/feed_bloc/bloc.dart';
import '../../blocs/feed_bloc/feed_state.dart';
import './post.dart';
import '../loader.dart';

class Feed extends StatefulWidget 
  Feed( Key key ): super(key: key);

  @override
  _FeedState createState() => _FeedState();


class _FeedState extends State<Feed> 
  final _scrollController = ScrollController();
  final _scrollThreshold = 300.0;
  FeedBloc _feedBloc;

  _FeedState();

  @override
  void initState() 
    super.initState();
    _scrollController.addListener(_onScroll);
    _feedBloc = BlocProvider.of<FeedBloc>(context);
  

  @override
  Widget build(BuildContext context) 
    return BlocBuilder<FeedBloc, FeedState>(
      builder: (context, state) 
        if (state is FeedUninitialized) 
          _feedBloc.add(Init());
          return Loader();
        

        if (state is FeedLoading) 
          return Loader();
        

        if (state is FeedLoaded) 
          return new RefreshIndicator(
            child: ListView(
              controller: _scrollController,
              // Important: Remove any padding from the ListView.
              padding: EdgeInsets.zero,
              children: state.posts.map((post) 
                return Post(
                  postModel: state.postMap[post]
                );
              ).toList(),
            ),
            onRefresh: () 
              _feedBloc.add(Refresh());
              return new Future.delayed(new Duration(seconds: 1));
            ,
          );
        


        return Center(
          child: SizedBox(
            height: 33,
            child: Text(
              'Sorry, there was a problem loading the feed.',
              style: TextStyle( color: Colors.white)
            ),
          ),
        );
      
    );
  

  int lastScroll = 0;
  void _onScroll() 
    if (new DateTime.now().millisecondsSinceEpoch - lastScroll > 1000) 
      lastScroll = new DateTime.now().millisecondsSinceEpoch;
      final maxScroll = _scrollController.position.maxScrollExtent;
      final currentScroll = _scrollController.position.pixels;
      if (maxScroll - currentScroll <= _scrollThreshold) 
        _feedBloc.add(Fetch());
      
    
  

我认为你需要的是 startAfterDocument。见下文...

Future<Map<String, dynamic>> getPosts(PostModel parent, PostModel lastPost) async 
    // First, we create the initial query. 
    // We pass in the parent key if there is one.
    Query query = Firestore.instance
      .collection('posts');

      if (parent != null) 
        query = query.where('parentId', isEqualTo: parent.key);
       else 
        query = query.where('parentId', isNull: true);
      

      query = query.orderBy('timestamp', descending: true);

    // If we want to start at a certain doc (user is scrolling throught he feed)
    // then we specify to start after a certain doc
    if (lastPost != null) 
      query = query.startAfterDocument(lastPost.rawDoc);
    

    // Execute the query
    final results = await query
      .limit(18)
      .getDocuments();

    // Create some Lists/Maps we're going to need
    List<String> posts = new List<String>();
    Map<String, PostModel> postMap = new Map<String, PostModel>();
    Map<String, bool> likeMap = new Map<String, bool>();

    // Convienience/Brevity 
    final List<DocumentSnapshot> documents = results.documents;
    final int numDocs = documents.length;

    if (numDocs > 0) 
      final firstDoc = results.documents[0].data;
      final lastDoc = results.documents[numDocs-1].data;

      // Get all your likes for a certain date range that aligns with the
      // documents we just retrieved
      likeMap = await getLikes(firstDoc['postCreated'], lastDoc['postCreated']);
    

    // Loop through, and create all the PostModels
    for (int i = 0; i < numDocs; i++) 
      DocumentSnapshot doc = documents[i];
      PostModel post = snapshotToPostModel(doc, likeMap[doc.documentID]);
      postMap[doc.documentID] = post;
      posts.add(post.key);
    

    final Map<String, dynamic> res = new Map<String, dynamic>();

    res['posts'] = posts;
    res['postMap'] = postMap;

    return res;
  

【讨论】:

这不能回答我的问题,但感谢您的努力..我正在尝试找出如何订购下一组数据,它startsAfter()最后一组数据是最初加载到屏幕上。 @alex 我明白了。我编辑了我的答案以包含实际查询 firestore 的代码。我想你可能需要startAftrerDocument。旁注:我感觉到你的痛苦。 dart/flutter 中的 firebase 文档不是很好。祝你好运! 如果我的编辑成功了,我稍后会回来并让我的回复更简洁地回答您的问题。 是的,我需要 startAfterDocument 让我试试看这是否可行..但它很有帮助,所以我会对此表示赞成..

以上是关于如何在列表视图的滚动中添加更多项目?的主要内容,如果未能解决你的问题,请参考以下文章

如何滚动到添加到 MVVM Light 列表视图中的新项目

如何实现在动态布局中添加更多视图在android中实现滚动视图

Swift 在可滚动列表中添加项目

如何在 kotlin 的 Recycler View Adapter 中添加更多数据列表而不清除先前的数据?

如何自动滚动到网格视图的末尾?

从上到下滚动时如何自动停止对项目的列表视图取消选择?