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

如何将flutter_wizard与go_router结合实现返回上一步功能?

Flutter向导流程与GoRouter兼容问题解决方案

问题描述

我正在开发一款包含多步骤流程的应用,页面结构如下:

  • Screen A
    • ...
  • Screen B
    • Flow
      • Wizard Screen 1
      • Wizard Screen 2
      • Wizard Screen 3
      • ...
    • ...
  • Screen C
    • ....
  • ...

希望用向导模式安排Flow内的步骤,同时搭配静态工具栏根据当前步骤更新内容。选用flutter_wizard包后,搭配GoRouter路由时,从第二步返回第一步会直接退出整个流程回到应用入口,目前未找到解决方法,考虑过将每个步骤定义为独立路由但不确定兼容性,最坏打算弃用向导库实现单独页面。

解决方案

方案1:将整个向导流程作为单个GoRouter路由节点

把Screen B下的Flow整体注册为GoRouter的一个独立路由,内部完全由flutter_wizard管理步骤切换。这样GoRouter的路由栈中只会存在这个Flow路由,向导内部的回退操作不会触发全局路由的pop。

示例路由配置:

final GoRouter _router = GoRouter(
  routes: [
    // 其他路由...
    GoRoute(
      path: '/screen-b/flow',
      builder: (context, state) => const WizardFlowWrapper(),
    ),
  ],
);

WizardFlowWrapper内部实现向导逻辑:

class WizardFlowWrapper extends StatelessWidget {
  const WizardFlowWrapper({super.key});

  @override
  Widget build(BuildContext context) {
    return FlutterWizard(
      toolbarBuilder: (context, state) {
        // 自定义静态工具栏,根据state.currentStep等参数更新内容
        return Container(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text('当前步骤:${state.currentStep + 1}/${state.totalSteps}'),
              ElevatedButton(
                onPressed: state.canGoNext ? () => FlutterWizard.of(context).next() : null,
                child: const Text('下一步'),
              ),
            ],
          ),
        );
      },
      steps: const [
        WizardStep(child: WizardScreen1()),
        WizardStep(child: WizardScreen2()),
        WizardStep(child: WizardScreen3()),
      ],
    );
  }
}

方案2:拦截系统返回事件,交由flutter_wizard处理

在向导流程页面中使用WillPopScope包裹flutter_wizard,拦截系统返回操作,优先让向导内部处理回退,只有当向导无法回退时,才允许GoRouter执行全局pop。

示例代码:

class WizardFlowWrapper extends StatelessWidget {
  const WizardFlowWrapper({super.key});

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        final wizard = FlutterWizard.of(context);
        if (wizard.canGoBack) {
          // 执行向导内部回退
          wizard.previous();
          return false; // 阻止系统默认的pop行为
        }
        // 无法回退时,允许退出流程
        return true;
      },
      child: FlutterWizard(
        toolbarBuilder: (context, state) => YourCustomToolbar(state: state),
        steps: const [
          WizardStep(child: WizardScreen1()),
          WizardStep(child: WizardScreen2()),
          WizardStep(child: WizardScreen3()),
        ],
      ),
    );
  }
}

方案3:纯GoRouter实现向导流程

如果不想依赖flutter_wizard,可以将每个向导步骤作为GoRouter的子路由,在Flow的父页面中保留静态工具栏,通过路由参数或状态管理同步步骤信息。

示例路由配置:

final GoRouter _router = GoRouter(
  routes: [
    // 其他路由...
    GoRoute(
      path: '/screen-b/flow',
      builder: (context, state) => const FlowParentScreen(),
      routes: [
        GoRoute(path: 'step1', builder: (context, state) => const WizardScreen1()),
        GoRoute(path: 'step2', builder: (context, state) => const WizardScreen2()),
        GoRoute(path: 'step3', builder: (context, state) => const WizardScreen3()),
      ],
    ),
  ],
);

FlowParentScreen作为外壳包含工具栏和子路由内容:

class FlowParentScreen extends StatelessWidget {
  const FlowParentScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final location = GoRouterState.of(context).location;
    // 根据当前路由路径判断步骤
    final currentStep = location.split('/').last;

    return Scaffold(
      appBar: AppBar(title: const Text('向导流程')),
      body: Column(
        children: [
          // 静态工具栏
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text('当前步骤:${_getStepNumber(currentStep)}'),
                ElevatedButton(
                  onPressed: () => _navigateToNextStep(context, currentStep),
                  child: const Text('下一步'),
                ),
              ],
            ),
          ),
          // 显示当前步骤页面
          const Expanded(child: RouterOutlet()),
        ],
      ),
    );
  }

  int _getStepNumber(String step) {
    switch (step) {
      case 'step1': return 1;
      case 'step2': return 2;
      case 'step3': return 3;
      default: return 1;
    }
  }

  void _navigateToNextStep(BuildContext context, String currentStep) {
    switch (currentStep) {
      case 'step1':
        context.go('/screen-b/flow/step2');
        break;
      case 'step2':
        context.go('/screen-b/flow/step3');
        break;
      case 'step3':
        // 完成流程,返回上一级
        context.pop();
        break;
    }
  }
}

总结

优先尝试方案1和方案2,能保留flutter_wizard的便捷性,快速解决路由冲突问题;方案3适合完全依赖GoRouter生态的场景,实现更灵活但需要额外处理步骤状态同步。

内容的提问来源于stack exchange,提问作者Tobias W.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:33:16