如果ListView比較長的話,直接listScrollController.position.maxScrollExtent是只能滾到距離最底有一定距離的地方。
原理貼在最后。
方法0:加上額外的滾動距離
缺點:iOS和web上會有嚴重的反彈效果,并且效果期間無法操作。
方法1:Scrollable.ensureVisible(BuildContext)
缺點:根本不可行。item較多時,靠后的item沒渲染過,沒有對應(yīng)的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組件獲取控件位置尺寸實現(xiàn)的幾個高級效果和功能(https://juejin.cn/post/6844903650737782792)
大概原理上是利用Rect記錄所有item的位置,循環(huán)jumpTo,直到目標item出現(xiàn)在屏幕內(nèi)。和方法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
缺點:卡頓。類似于循環(huán)滾動。沒有計算padding。
========================================================================
ListView的滾動原理:
https://mp.weixin.qq.com/s/itsrBAry7cZKmLGmLym62g
https://juejin.cn/post/6844904008339947528
https://juejin.cn/post/6844904015994552333
//ListView滾動的最大值估算。可以直接在SDK的framework源碼中打印調(diào)試。
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;
}
我自己畫的草圖: