关闭应用后重新打开如何回到ListView的同一滚动位置
长ListView滚动位置记忆实现方案
核心实现逻辑分为两步:首先监听列表滚动位置变化,实时持久化存储位置信息;应用重启/页面再次打开时,读取存储的位置信息,等列表渲染完成后主动滚动到对应位置即可。
Android 原生实现
- 持久化存储选用
SharedPreferences即可满足需求 - 滚动位置监听与保存代码:
listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // 滚动停止后再保存位置,避免频繁IO if (scrollState == SCROLL_STATE_IDLE) { int firstVisiblePos = listView.getFirstVisiblePosition(); View firstVisibleView = listView.getChildAt(0); int topOffset = firstVisibleView == null ? 0 : firstVisibleView.getTop() - listView.getPaddingTop(); SharedPreferences sp = getSharedPreferences("list_scroll_config", MODE_PRIVATE); sp.edit() .putInt("last_first_pos", firstVisiblePos) .putInt("last_top_offset", topOffset) .apply(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {} });
- 位置恢复代码:
SharedPreferences sp = getSharedPreferences("list_scroll_config", MODE_PRIVATE); int lastFirstPos = sp.getInt("last_first_pos", 0); int lastOffset = sp.getInt("last_top_offset", 0); // 等列表布局渲染完成后再执行滚动,避免失效 listView.post(() -> listView.setSelectionFromTop(lastFirstPos, lastOffset));
Flutter 实现
- 选用
shared_preferences库做持久化,配合ScrollController监听滚动偏移 - 示例代码:
final ScrollController _listScrollController = ScrollController(); late SharedPreferences _sp; @override void initState() { super.initState(); _initStorageAndRestorePosition(); // 监听滚动偏移,实时存储 _listScrollController.addListener(() { if (_listScrollController.position.hasPixels) { _sp.setDouble('list_scroll_offset', _listScrollController.offset); } }); } void _initStorageAndRestorePosition() async { _sp = await SharedPreferences.getInstance(); double lastScrollOffset = _sp.getDouble('list_scroll_offset') ?? 0; // 等待列表第一帧渲染完成后再滚动 WidgetsBinding.instance.addPostFrameCallback((_) { if (_listScrollController.hasClients) { _listScrollController.jumpTo(lastScrollOffset); } }); } @override Widget build(BuildContext context) { return ListView.builder( controller: _listScrollController, itemCount: 1000, itemBuilder: (context, index) => ListTile(title: Text('列表项 $index')), ); }
iOS 原生实现
- 选用
UserDefaults存储位置信息,监听滚动停止事件 - 示例代码:
// 滚动停止时保存位置 func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let scrollOffset = tableView.contentOffset.y UserDefaults.standard.set(scrollOffset, forKey: "list_last_scroll_offset") } // 页面加载完成后恢复位置 override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let lastOffset = UserDefaults.standard.double(forKey: "list_last_scroll_offset") tableView.setContentOffset(CGPoint(x: 0, y: lastOffset), animated: false) }
注意事项
- 必须等列表数据加载完成、布局渲染完毕后再执行滚动操作,否则会出现定位失效的问题
- 如果列表项高度为动态变化的场景,优先存储第一个可见项索引+该项顶部距离列表顶部的偏移量,不要只存全局滚动偏移,避免列表项高度变化后定位不准
- 滚动监听可添加防抖逻辑,避免滚动过程中频繁触发持久化写入,影响性能
内容的提问来源于stack exchange,提问作者Hicham
相关产品推荐
相关产品推荐

