firebase - Flutter ListView 跳转到顶部

我正在为我的应用创建新闻提要,当我向下滚动时,将从 Firestore 获取数据。一旦我向上滚动, ListView 就会立即捕捉到最顶部,从而跳过中间的所有其他项目。如果我用静态数据加载 ListView ,它可以正常工作,但是当我从 Firestore 中提取数据时,问题再次出现。我不确定是什么导致了这种行为。

Video demonstrating the irregular scrolling 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, 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.

Solution :

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. 将代码中的 FutureBuilder 替换为 KeepAliveFutureBuilder。
  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 表示我们希望这个 child 保持事件状态。

https://stackoverflow.com/questions/51536756/

相关文章:

android - Flutter中如何解析json数据并显示在Listview中?

firebase - 如何在 Flutter 中设置不同的 firebase 环境

firebase - 如何使用 Firebase 在 Flutter 中进行电话身份验证?

firebase - flutter |如何将数据添加到 Firestore 中的现有文档

android - Flutter - 多个手势,无需抬起手指

dart - 如何删除 RadioListTile 上的内部填充,以便可以连续使用 3 个 Radi

dart - 使用 Flutter 进行底部导航

android - 如何在 Flutter 中禁用发布版本中的所有日志 [debugPrint()]

dart - 如何使用现有的应用程序 keystore 获取签名的 apk?

android-studio - Flutter - 尝试运行 Flutter 应用程序时模拟器未启