在顶部添加新项目时在 ListView 中保持滚动位置

Posted

技术标签:

【中文标题】在顶部添加新项目时在 ListView 中保持滚动位置【英文标题】:Keep scroll position in ListView when adding new item on top 【发布时间】:2019-01-21 12:13:47 【问题描述】:

我正在使用ListView.builder 进行聊天。

场景如下:用户输入新的聊天消息,当发生这种情况时,我将新消息存储在状态中,因此itemCount 增加了 1。

如果我在列表的末尾,我直接在顶部看到新项目,一切正常。

但是,如果我在聊天过程中添加了一个项目,则视图会滚动一点。如何禁用此行为?我想这有点道理,因为滚动偏移在ScrollControllers 状态下仍然是相同的double,但是如果还有一个项目,它看起来就像滚动...

有什么好办法吗?我猜手动方法是测量新项目的高度并再次手动设置正确的 ScrollController 偏移量.. 但是我

【问题讨论】:

我认为“手动方法”是正确的方法,因为您正在重建ListView 为它提出问题。这应该是原生包含在较低层中的。您不应该手动计算大小 这对动态高度的项目有什么解决方案吗?我有完全相同的问题。 还需要解决方案,有什么消息吗? 【参考方案1】:

这是在列表顶部添加静态/恒定高度(高度:100)的项目的解决方案。

当我检测到列表长度已更改时,我通过调用 _scrollController.jumpTo(newOffect) 以硬编码项目高度更改偏移位置。

效果很好。当一个新项目被添加到顶部时,列表保持在当前位置,没有可见的跳转。

class FeedWidget extends StatefulWidget 
  FeedWidget(
    Key key,
  ) : super(key: key);

  @override
  State<StatefulWidget> createState() => _FeedWidgetState();


class _FeedWidgetState extends State<FeedWidget> 
  var _scrollController = ScrollController();
  var _itemsLength = 0;

  @override
  Widget build(BuildContext context) 
    return StreamBuilder<List<FeedItem>>(
      stream: Provider.of<FeedRepository>(context).getAll(),
      builder: (BuildContext context, AsyncSnapshot<List<FeedItem>> items) 
        print('Loaded feed data $items');
        switch (items.connectionState) 
          case ConnectionState.waiting:
            return Center(child: CircularProgressIndicator());
          default:
            final newItemsLength = items.data.length;
            if (_itemsLength != 0 && _itemsLength != newItemsLength) 
              final newItemsCount = newItemsLength - _itemsLength;
              print('New items detected: $newItemsCount');
              final newOffset = _scrollController.offset +
                  100 * newItemsCount; //item height is 100
              print(
                  'Setting new offest $_scrollController.offset -> $newOffset');
              _scrollController.jumpTo(newOffset);
            
            print('Items length new = $newItemsLength old = $_itemsLength');
            _itemsLength = newItemsLength;
            return Flexible(
                child: ListView(
                    key: PageStorageKey('feed'), //keeps scroll position
                    controller: _scrollController,
                    padding: EdgeInsets.only(top: 8, bottom: 32),
                    children: items.data
                        .map((element) => FeedItemCard(item: element)) //item height is 100
                        .toList()));
        
      ,
    );
  


【讨论】:

【参考方案2】:

事实上,您不应该将新的聊天项目添加到列表中。而且您必须缓存它们,然后在列表到达顶部或底部后将缓存注入列表中。我希望这个解决方案对你有用。

【讨论】:

我们必须提供改变 ListView 行为的解决方案,而不是建议解决方法。

以上是关于在顶部添加新项目时在 ListView 中保持滚动位置的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 中的顶部 ListView 项目上方(以及最后一个项目下方)添加边距

滚动到顶部时在表格视图的开头动态添加行

我想在滚动时在列表视图中添加 500 张图像,并删除当前不在屏幕上的项目

滚动ListViewItem位于ListView的顶部

更新 SimpleCursorAdapter,同时保持 ListView 中的滚动位置

ListView 项目在滚动后保持突出显示