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

Flutter(GoRouter)如何预加载路由或让Widget离屏时保持加载?

解决GoRouter下QuillHtmlEditor页面重复加载的问题

要实现QuillHtmlEditor页面始终保持加载状态、避免每次导航重建,最简便的方案是利用页面状态保持容器结合GoRouter的路由配置,以下是两种可行的实现方式:

方式一:自定义IndexedStack容器管理页面状态

将需要预加载的页面统一放在IndexedStack中,切换路由时仅切换容器的索引,页面不会被销毁重建。

1. 创建全局页面容器

class AppContainer extends StatefulWidget {
  const AppContainer({super.key});

  @override
  State<AppContainer> createState() => _AppContainerState();
}

class _AppContainerState extends State<AppContainer> {
  int _currentPageIndex = 0;
  // 预加载所有需要保持状态的页面
  final List<Widget> _pages = const [
    HomePage(),
    QuillEditorPage(), // 你的富文本编辑器页面
    SettingsPage(),
  ];

  // 提供切换页面的方法
  void switchPage(int index) {
    setState(() {
      _currentPageIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return IndexedStack(
      index: _currentPageIndex,
      children: _pages,
    );
  }
}

2. 配置GoRouter路由

让路由指向容器,通过路由跳转时触发页面索引切换:

final GoRouter router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const AppContainer(),
      routes: [
        GoRoute(
          path: 'home',
          builder: (context, state) {
            (context.findAncestorStateOfType<_AppContainerState>() as _AppContainerState).switchPage(0);
            return const SizedBox.shrink();
          },
        ),
        GoRoute(
          path: 'editor',
          builder: (context, state) {
            (context.findAncestorStateOfType<_AppContainerState>() as _AppContainerState).switchPage(1);
            return const SizedBox.shrink();
          },
        ),
        GoRoute(
          path: 'settings',
          builder: (context, state) {
            (context.findAncestorStateOfType<_AppContainerState>() as _AppContainerState).switchPage(2);
            return const SizedBox.shrink();
          },
        ),
      ],
    ),
  ],
);

3. 给Quill页面添加保活

在Quill编辑器页面混入AutomaticKeepAliveClientMixin,确保页面状态不被回收:

class QuillEditorPage extends StatefulWidget {
  const QuillEditorPage({super.key});

  @override
  State<QuillEditorPage> createState() => _QuillEditorPageState();
}

class _QuillEditorPageState extends State<QuillEditorPage> with AutomaticKeepAliveClientMixin {
  late QuillHtmlEditorController _editorController;

  @override
  bool get wantKeepAlive => true; // 开启页面保活

  @override
  void initState() {
    super.initState();
    // 仅初始化一次编辑器
    _editorController = QuillHtmlEditorController();
    // 这里可以加载初始内容、配置编辑器,只会执行一次
  }

  @override
  Widget build(BuildContext context) {
    super.build(context); // 必须调用此方法触发保活逻辑
    return Scaffold(
      body: QuillHtmlEditor(
        controller: _editorController,
        // 你的编辑器配置
      ),
    );
  }
}

方式二:使用GoRouter的StatefulShellRoute(底部导航场景)

如果你的App是底部导航结构,直接用GoRouter内置的StatefulShellRoute,它会自动用IndexedStack管理各分支页面的状态,无需手动实现容器:

final GoRouter router = GoRouter(
  routes: [
    StatefulShellRoute.indexedStack(
      builder: (context, state, navigationShell) {
        return Scaffold(
          body: navigationShell,
          bottomNavigationBar: BottomNavigationBar(
            currentIndex: navigationShell.currentIndex,
            onTap: (index) {
              navigationShell.goBranch(
                index,
                initialLocation: index == navigationShell.currentIndex,
              );
            },
            items: const [
              BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
              BottomNavigationBarItem(icon: Icon(Icons.edit), label: '编辑器'),
              BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'),
            ],
          ),
        );
      },
      branches: [
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/home',
              builder: (context, state) => const HomePage(),
            ),
          ],
        ),
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/editor',
              builder: (context, state) => const QuillEditorPage(),
            ),
          ],
        ),
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/settings',
              builder: (context, state) => const SettingsPage(),
            ),
          ],
        ),
      ],
    ),
  ],
);

这种方式下,切换底部导航时,Quill页面会保持之前的加载状态,不会重新初始化。

关键注意点

  • 确保Quill的初始化逻辑(如加载内容、配置控制器)放在initState中,仅执行一次;
  • 如果使用状态管理(如Provider、GetX),可以替代直接查找父状态的方式,让页面切换逻辑更优雅;
  • 若App不是底部导航结构,方式一的自定义IndexedStack容器是更通用的解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 05:35:25