FlutterFlutterFlutter

[flutter] Item高度不固定的ListView如何sc

2021-05-06  本文已影响0人  ccsosnfs

如果ListView比较长的话,直接listScrollController.position.maxScrollExtent是只能滚到距离最底有一定距离的地方。
原理贴在最后。

方法0:加上额外的滚动距离
缺点:iOS和web上会有严重的反弹效果,并且效果期间无法操作。

方法1:Scrollable.ensureVisible(BuildContext)
缺点:根本不可行。item较多时,靠后的item没渲染过,没有对应的RenderObject。

方法2:第一次animateTo后,判断maxScrollExtent是否和第一次前的估算值一致,不一致的话,再滚动一次。

        listScrollController.animateTo(maxScrollExtent, duration: Duration(milliseconds: 200), curve: Curves.linear)
            .whenComplete(() {
          if (!listScrollController.hasClients) return;
          var after = listScrollController.position.maxScrollExtent;

          if (after > maxScrollExtent)
            listScrollController.animateTo(after, duration: Duration(milliseconds: 200), curve: Curves.linearToEaseOut);
        });

缺点:由于是拼接两次滚动,只能使用Curves.linear,否则能看出来有明显的拼接感。并且依然无法滚动到指定item。

方法3:利用RectGetter组件获取控件位置尺寸实现的几个高级效果和功能(https://juejin.cn/post/6844903650737782792)
大概原理上是利用Rect记录所有item的位置,循环jumpTo,直到目标item出现在屏幕内。和方法2类似。

方法4:使用https://pub.dev/packages/scrollable_positioned_list
大概原理是使用一个辅助列表来记录所有widget的高度
源自大佬的博客 https://blog.bombox.org/2020-06-30/flutter-chat-listview/
缺点:没有使用原生ListView,侵入性强。

方法5:https://pub.dev/packages/indexed_list_view
这个只能适用于无限高度的列表,所以也就没有底部。

方法6:https://pub.dev/packages/scroll_to_index
缺点:卡顿。类似于循环滚动。没有计算padding。

========================================================================
ListView的滚动原理:
https://mp.weixin.qq.com/s/itsrBAry7cZKmLGmLym62g
https://juejin.cn/post/6844904008339947528
https://juejin.cn/post/6844904015994552333

//ListView滚动的最大值估算。可以直接在SDK的framework源码中打印调试。
  static double _extrapolateMaxScrollOffset(
    int firstIndex,
    int lastIndex,
    double leadingScrollOffset,
    double trailingScrollOffset,
    int childCount,
  ) {
    if (lastIndex == childCount - 1)
      return trailingScrollOffset;
    final int reifiedCount = lastIndex - firstIndex + 1;
    //算出平均值
    final double averageExtent = (trailingScrollOffset - leadingScrollOffset) / reifiedCount;
    //加上剩余估计值
    final int remainingCount = childCount - lastIndex - 1;
    return trailingScrollOffset + averageExtent * remainingCount;
  }

我自己画的草图:


ListView.png
上一篇 下一篇

猜你喜欢

热点阅读