ListVIew在再次构建后无法滚动到正确的偏移位置 [英] ListVIew doesn't scroll to the correct offset position after its built again

查看:96
本文介绍了ListVIew在再次构建后无法滚动到正确的偏移位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望列表视图以偏移量开头.我正在尝试通过在ListView中使用以下代码来实现这一点.

I want the listview to start with an offset. Which I am trying to achieve by using below code in the ListView.

控制器:ScrollController(initialScrollOffset:30 * ITEM_HEIGHT),

controller: ScrollController(initialScrollOffset: 30 * ITEM_HEIGHT),

首先在第一次加载时以正确的偏移量加载列表.

Initially on the first load the list is loaded with the correct offset.

通过从父窗口小部件调用set状态再次构建列表时,列表会更新,但是滚动偏移的行为很奇怪.

When the list is built again by calling set state from the parent widget, the list gets updated but the scroll offset behaves weird.

有两种情况:

  1. 我不滚动列表:此后,如果调用了set状态,则一切正常.列表会更新,并且始终处于正确的偏移量.
  2. 我滚动列表:如果我滚动列表然后重建列表, 滚动偏移量关闭了一些项目.该列表已更新,这很好.
  1. I don't scroll the list: After this if the set state is called everything works fine. List gets updated and is always at the correct offset.
  2. I scroll the list: if I scroll the list and then the list is rebuilt, the scroll offset is off by a few items. The list gets updated which is fine.

是因为我滚动时会保留最后一个滚动位置,这会抵消我的计算结果吗?我认为这不应该发生,因为它是状态少的小部件.

Is it because when I scroll it keeps the last scroll position and that offsets my calculation? Which I think should not happen as it is a state less widget.

class DaysManager extends StatelessWidget {
  final int daysBeforeFocusDate = 30;
  final int totalDaysToInit = 61;
  static final double ITEM_HEIGHT = 108.00;

  ScrollController scrollController;

  List<Day> days;

  DaysManager({DateTime focusDate}) {
      final DateTime startDate =
      focusDate.subtract(Duration(days: daysBeforeFocusDate));
      days = List.generate(totalDaysToInit, (int index) {
      return Day(
       date: startDate.add(
        Duration(days: index),
    ),
  );
});

scrollController = ScrollController(initialScrollOffset: 30 *ITEM_HEIGHT);
}

  @override
  Widget build(BuildContext context) {
   return _buildScrollView();
  }

  ListView _buildScrollView() {
    ListView listView = ListView.builder(
    cacheExtent: 0,
    controller: scrollController,
    itemCount: days.length,
    itemBuilder: (BuildContext context, int index) {
      return days[index];
     });

    return listView;
  }
 }

推荐答案

我接触了Flutter Slack社区,并得到了可行的答案.全部归功于那边的楼首.这是谈话内容的副本.

I reached out the the Flutter Slack community and got an answer that works. All credit to Loushou over there. Here's a copy of that conversation.

ScrollController将其滚动位置保存在其所附的列表的PageStorage记录内……而不是其自己的PageStorage.因此,在重新创建窗口小部件时,由于您没有为列表视图窗口小部件指定新的key,因此它会重用相同的键(为提高性能而进行内部优化的众多优化之一).您可以通过添加两行来解决此问题:

ScrollController saves it’s scroll position inside the PageStorage record of the list it is attached to… not of it’s own PageStorage. because of this, when the widget is recreated, since you do not specify a new key for the listview widget, it reuses the same key (one of the many optimizations internal to flutter for performance). you can solve this by adding two lines:

import 'dart:math';
...
ListView listView = ListView.builder(
  key: ValueKey<int>(Random(DateTime.now().millisecondsSinceEpoch).nextInt(4294967296)),
...

每次重新创建列表时,都需要给列表视图一个新的随机key,以免加载它的PageStorage值.

You need to give the listview a new, random key every time you recreate it, so that it does not load up it’s PageStorage values.

这是示例代码中DaysManager的完整,更新代码:

here is the full, updated code for DaysManager from your example code:

class DaysManager extends StatelessWidget {
  final int daysBeforeFocusDate = 30;
  final int totalDaysToInit = 61;
  static final double ITEM_HEIGHT = 108.00;

  ScrollController scrollController;

  List<Day> days;

  DaysManager({
    DateTime focusDate,
  }) {
    final DateTime startDate = focusDate.subtract(Duration(days: daysBeforeFocusDate));
    days = List.generate(totalDaysToInit, (int index) {
      return Day(
        date: startDate.add(
          Duration(days: index),
        ),
      );
    });

    scrollController = ScrollController(
      initialScrollOffset: 30 *ITEM_HEIGHT,
    );
  }

  @override
  Widget build(BuildContext context) {
    return _buildScrollView();
  }

  ListView _buildScrollView() {
    ListView listView = ListView.builder(
      key: ValueKey<int>(Random(DateTime.now().millisecondsSinceEpoch).nextInt(4294967296)),
      cacheExtent: 0,
      controller: scrollController,
      itemCount: days.length,
      itemBuilder: (BuildContext context, int index) {
        return days[index];
      });

    return listView;
  }
}

这篇关于ListVIew在再次构建后无法滚动到正确的偏移位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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