Flutter ListView跳到顶部 [英] Flutter ListView Jumps To Top

查看:1878
本文介绍了Flutter ListView跳到顶部的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的应用程序创建一个新闻提要,并在向下滚动时从Firestore提取数据。当我向上滚动列表视图时,它就会立即跳到最顶部,从而跳过它们之间的所有其他项。如果我向列表视图加载静态数据,则该列表视图工作正常,但是当我从Firestore中提取数据时,该问题再次出现。我不确定是什么原因导致了这种行为。

I am creating a news feed for my app and as I scroll down data is fetched from Firestore. As soon as I scroll up the listview literally snaps to the very top skipping all the other items in between. The listview works fine if I load it with static data but when i pull data from Firestore, the issue reemerges. I am not sure what's causing this behaviour.

视频演示了不规则滚动行为

这是我的代码

return StreamBuilder(
            stream: Firestore.instance.collection(Constants.NEWS_FEED_NODE)
                .document("m9yyOjsPxV06BrxUtHdp").
            collection(Constants.POSTS_NODE).orderBy("timestamp",descending: true).snapshots(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (!snapshot.hasData)
                return Center(child: CircularProgressIndicator(),);

              if (snapshot.data.documents.length == 0)
                return Container();
              //after getting the post ids, we then make a call to FireStore again
              //to retrieve the details of the individual posts
              return ListView.builder(
                  itemCount: snapshot.data.documents.length,
                  itemBuilder: (_, int index) {
                    return FeedItem2(feed: Feed.fireStore(
                        snapshot: snapshot.data.documents[index]),);
                  });
            },
          );


推荐答案

问题原因:


ListView ScrollViews 通常处置屏幕上当前不可见的子级。当我们尝试滚动回到子级时,将从头开始重新初始化该子级。但是在这种情况下,我们的孩子是FutureBuilder。重新初始化它会在短短的一秒钟内再次创建进度指示器,然后再次创建页面。这会混淆滚动机制,以非确定性的方式抛出我们。

ListView, and ScrollViews in general, tend to dispose of the children that are not currently visible on the screen. When we try to scroll back to the child, the child is reinitialized from scratch. But in this case, our child is a FutureBuilder; re-initializing it creates a progress indicator again just for a part of a second, then creates the page once again. This confuses the scrolling mechanism, throwing us around in non-deterministic ways.

解决方案


一种解决方法是确保进度指示器的页面大小完全相同,但是在大多数情况下,这不太实用。因此,我们将诉诸一种效率较低的方法,但它将解决我们的问题。我们将阻止ListView处理子项。为了做到这一点,我们需要包装每个孩子,即每个 FutureBuilder 和一个 AutomaticKeepAliveClientMixin 。这种混入让孩子们即使在屏幕外时也要求父母让他们保持生命,这将解决我们的问题。因此:

One way to solve this is to make sure that the progress indicator has the exact same size of the page, but in most cases, that is not too practical. So, we will resort to a method that is less efficient, but that will solve our problems; we will prevent ListView from disposing of the children. In order to do that, we need to wrap each child — that is, each FutureBuilder, with an AutomaticKeepAliveClientMixin. This mixin makes the children ask their parent to keep them alive even when off-screen, which will solve our problem. So:




  1. 用KeepAliveFutureBuilder在代码中替换FutureBuilder。

  2. 创建KeepAliveFutureBuilder小部件:





class KeepAliveFutureBuilder extends StatefulWidget {

  final Future future;
  final AsyncWidgetBuilder builder;

  KeepAliveFutureBuilder({
    this.future,
    this.builder
  });

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

class _KeepAliveFutureBuilderState extends State<KeepAliveFutureBuilder> with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: widget.future,
      builder: widget.builder,
    );
  }

  @override
  bool get wantKeepAlive => true;
}




  • 此小部件只是FutureBuilder的包装。它是一个StatefulWidget,其State通过AutomaticKeepAliveClientMixin扩展了State类。

  • 它实现了wantKeppAlive getter,并使其简单地返回true,以表示要ListView我们希望这个孩子成为保持生命。

  • 这篇关于Flutter ListView跳到顶部的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆