fluttercandies / flutter_scrollview_observer

A widget for observing data related to the child widgets being displayed in a ScrollView. Maintainer: @LinXunFeng
https://pub.dev/packages/scrollview_observer
MIT License
438 stars 47 forks source link

chatObserver.standby();无法保持位置不动 #73

Closed yangqiuyan closed 7 months ago

yangqiuyan commented 8 months ago

Platforms

dart, Android

Description

往列表位置 0,插入N 条数据,写了chatObserver.standby(changeCount: N);,列表还是滚动到最上面了,没有保持列表不动。

My code

// 列表上层
Selector<modle, List<>>(
  builder: , // list
  shouldRebuild: (previous, next) {
    // 列表长度发生变化时:全量刷新List;长度未发生变化时:不全量刷新(只刷新更新的item)
    int preLength = previous.length;
    int nextLength = next.length;
    bool shouldRebuild = preLength != nextLength;
    return shouldRebuild;
  },
  selector: (context, model) {
    return model.list;
  })

// 列表 widget
return Stack(
  alignment: Alignment.topCenter,
  children: [
    LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
          return ListViewObserver(
            controller: observerController,
            child: EasyRefresh.builder(
              controller: _refreshController,
              onRefresh: () async {
                **chatObserver.standby(changeCount: 16);**
                // 此处加载数据,notify 刷新列表
                _refreshController.resetFooter();
                IndicatorResult result = widget.model.haveMoreData
                    ? IndicatorResult.success
                    : IndicatorResult.noMore;
                _refreshController.finishRefresh(result);
              },
              childBuilder: (BuildContext context, ScrollPhysics physics) {
                var scrollViewPhysics =
                physics.applyTo(ChatObserverClampingScrollPhysics(
                  observer: chatObserver,
                ));
                Widget resultWidget = ListView.builder(
                    physics: scrollViewPhysics,
                    shrinkWrap: chatObserver.isShrinkWrap,
                    reverse: true,
                    controller: _autoScrollController,
                    itemBuilder: (context, index) {
                      return _buildMsgItem(index);
                    },
                    itemCount: list.length);
                if (chatObserver.isShrinkWrap) {
                  resultWidget = SingleChildScrollView(
                    reverse: true,
                    physics: scrollViewPhysics,
                    child: Container(
                      alignment: Alignment.topCenter,
                      child: resultWidget,
                      height: constraints.maxHeight + 0.001,
                    ),
                  );
                }
                return resultWidget;
              },
            ),
          );
        })
  ],
);

Try do it

No response

LinXunFeng commented 8 months ago

从代码上来看,猜测是因为没有找到保持位置的参照 item(一般也是因为这个原因~)。

可以看摘自 【Wiki - 3.1、基本使用】 的最后一段说明

注:该功能依赖被插入消息前的最新消息视图做为参照去计算偏移量,所以如果一次性插入的消息数太多,导致该参照消息视图无法得到渲染,则该功能会失效,需要你自己去对 ScrollViewcacheExtent 设置合理的值来尽量避免这个问题!

cacheExtent 建议的值为:单个item的最大高度 * 条数 + 250

如:一次最多播入 20 条消息,单条消息 item 的最大高度为 300,则 cacheExtent 建议的值为 300 * 20 + 250

yangqiuyan commented 8 months ago

实测添加了 cacheExtent 后,也无法保持位置不变

LinXunFeng commented 8 months ago

请提供可直接运行且可复现的 demo

xuyisheng commented 7 months ago

example中,_addMessage方法,将Line 351改成: chatModels.insert(chatModels.length - 1, ChatDataHelper.createChatModel()); 将内容插在顶部,这时列表无法保持不动,而原始代码,insert在0的时候,是可以的

LinXunFeng commented 7 months ago

example中,_addMessage方法,将Line 351改成: chatModels.insert(chatModels.length - 1, ChatDataHelper.createChatModel()); 将内容插在顶部,这时列表无法保持不动,而原始代码,insert在0的时候,是可以的

往后面加数据的话不需要保持位置,记得调用 observeSwitchShrinkWrap 即可。

_addMessage(int count) {
  setState(() {
    chatModels.insert(chatModels.length - 1, ChatDataHelper.createChatModel());
    chatObserver.observeSwitchShrinkWrap();
  });
}
LinXunFeng commented 7 months ago

因原问题太久未回复,该 issue 关闭,有需要可以再次打开