You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用go_router跳转详情页后返回,ResultsPage丢失滚动偏移且重建

解决Flutter Web端go_router跳转后ListView滚动偏移丢失问题

问题根源

Web端使用go_router的context.pushNamed(...)跳转时,原ResultsPage会被从Widget树中移除并销毁,返回时重新创建,导致所有状态(包括滚动偏移)被清空——这也是AutomaticKeepAliveClientMixin和页面内ScrollController记录偏移无效的核心原因:页面都销毁了,依附的状态自然留不住。

解决方案

方案1:用StatefulShellRoute嵌套路由(推荐)

通过嵌套路由让ResultsPage作为父路由的一部分,跳转详情页时仅在其上方叠加页面,不会销毁ResultsPage,滚动偏移自然保留。

路由配置示例:

final router = GoRouter(
  routes: [
    StatefulShellRoute.indexedStack(
      builder: (context, state, navigationShell) {
        return Scaffold(body: navigationShell);
      },
      branches: [
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/results',
              builder: (context, state) => ResultsPage(),
              routes: [
                GoRoute(
                  path: 'detail/:id',
                  builder: (context, state) => DetailPage(id: state.pathParameters['id']!),
                ),
              ],
            ),
          ],
        ),
      ],
    ),
  ],
);

跳转详情页时,ResultsPage会被保留在后台,返回时直接显示原页面,滚动位置完全不变,无需额外处理状态。

方案2:全局状态管理保存滚动偏移

如果无法修改路由结构,可将滚动偏移存储在全局状态中(比如Provider、Riverpod等状态管理库),页面重建时从全局读取并恢复。

以Riverpod为例:

  1. 定义全局状态Provider:
final scrollOffsetProvider = StateProvider<double>((ref) => 0.0);
  1. 在ResultsPage中使用:
class ResultsPage extends StatefulWidget {
  @override
  State<ResultsPage> createState() => _ResultsPageState();
}

class _ResultsPageState extends State<ResultsPage> {
  late ScrollController _scrollController;

  @override
  void initState() {
    super.initState();
    // 从全局状态读取上次的滚动偏移,作为初始值
    final initialOffset = ref.read(scrollOffsetProvider);
    _scrollController = ScrollController(initialScrollOffset: initialOffset);
    
    // 监听滚动,实时更新全局状态
    _scrollController.addListener(() {
      ref.read(scrollOffsetProvider.notifier).state = _scrollController.offset;
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SearchBar(),
        FilterBar(),
        Expanded(
          child: ListView.builder(
            controller: _scrollController,
            itemCount: 100,
            itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
          ),
        ),
      ],
    );
  }
}

这样即使页面重建,也能从全局状态中恢复之前的滚动位置。

方案3:PageStorage(慎用)

给ListView指定唯一的pageStorageKey,Flutter会自动保存滚动偏移,但Web端因路由机制可能导致PageStorage的存储被清空,可靠性不如前两种方案。

示例:

ListView.builder(
  key: const PageStorageKey('results_list'),
  // ...其他配置
)

内容的提问来源于stack exchange,提问作者user2232305

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:41:26