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

Flutter Stepper中实现多二维码扫描的问题求助

解决Stepper中多MobileScanner回调冲突的方案

问题核心在于Stepper组件默认会渲染所有步骤的内容(即使非当前步骤只是隐藏),导致两个MobileScanner实例同时处于活跃状态,所以扫描时两个onDetect都会触发。下面给出两种直接可行的解决思路:

方案一:只渲染当前步骤的MobileScanner

根据Stepper的activeStep状态,动态控制对应步骤的扫描器是否渲染,非当前步骤用空组件占位。这样同一时间只有一个扫描器在运行,从根源避免回调冲突。

示例代码:

int _activeStep = 0;

@override
Widget build(BuildContext context) {
  return Stepper(
    currentStep: _activeStep,
    onStepContinue: () {
      if (_activeStep < 1) {
        setState(() => _activeStep += 1);
      }
    },
    steps: [
      Step(
        title: const Text('扫描代金券'),
        content: _activeStep == 0 
            ? MobileScanner(
                onDetect: (capture) async {
                  final barcodes = capture.barcodes;
                  if (barcodes.isEmpty) return;
                  
                  final voucherCode = barcodes.first.rawValue!;
                  // 弹出验证进度弹窗
                  showDialog(
                    context: context,
                    barrierDismissible: false,
                    builder: (_) => const Center(child: CircularProgressIndicator()),
                  );
                  
                  // 执行司机权限验证逻辑
                  bool isValid = await _validateDriverPermission(voucherCode);
                  
                  Navigator.pop(context);
                  if (isValid) {
                    setState(() => _activeStep += 1);
                  }
                },
              )
            : const SizedBox.shrink(),
      ),
      Step(
        title: const Text('扫描车辆'),
        content: _activeStep == 1
            ? MobileScanner(
                onDetect: (capture) async {
                  final barcodes = capture.barcodes;
                  if (barcodes.isEmpty) return;
                  
                  final carCode = barcodes.first.rawValue!;
                  // 弹出验证进度弹窗
                  showDialog(
                    context: context,
                    barrierDismissible: false,
                    builder: (_) => const Center(child: CircularProgressIndicator()),
                  );
                  
                  // 执行车辆匹配验证逻辑
                  bool isMatch = await _validateCarMatch(carCode);
                  
                  Navigator.pop(context);
                  if (isMatch) {
                    // 验证完成后的后续逻辑,比如提交订单
                  }
                },
              )
            : const SizedBox.shrink(),
      ),
    ],
  );
}

// 模拟验证接口
Future<bool> _validateDriverPermission(String code) async {
  await Future.delayed(const Duration(seconds: 2));
  return true;
}

Future<bool> _validateCarMatch(String code) async {
  await Future.delayed(const Duration(seconds: 2));
  return true;
}

方案二:用控制器控制扫描器启停

如果需要保留所有步骤的组件状态(比如不想重新初始化扫描器),可以给两个扫描器分别绑定独立的MobileScannerController,在切换步骤时主动启停对应控制器。

示例代码:

int _activeStep = 0;
final MobileScannerController _voucherController = MobileScannerController();
final MobileScannerController _carController = MobileScannerController();

@override
void initState() {
  super.initState();
  // 初始启动代金券扫描器
  _voucherController.start();
}

@override
void dispose() {
  _voucherController.dispose();
  _carController.dispose();
  super.dispose();
}

void _switchStep(int newStep) {
  setState(() => _activeStep = newStep);
  // 切换时启停对应控制器
  if (newStep == 0) {
    _voucherController.start();
    _carController.stop();
  } else {
    _carController.start();
    _voucherController.stop();
  }
}

@override
Widget build(BuildContext context) {
  return Stepper(
    currentStep: _activeStep,
    onStepContinue: () => _switchStep(_activeStep + 1),
    onStepCancel: () => _switchStep(_activeStep - 1),
    steps: [
      Step(
        title: const Text('扫描代金券'),
        content: MobileScanner(
          controller: _voucherController,
          onDetect: (capture) async {
            // 代金券扫描逻辑同方案一
          },
        ),
      ),
      Step(
        title: const Text('扫描车辆'),
        content: MobileScanner(
          controller: _carController,
          onDetect: (capture) async {
            // 车辆扫描逻辑同方案一
          },
        ),
      ),
    ],
  );
}

两种方案对比

  • 方案一更轻量,非当前步骤的扫描器完全不渲染,节省资源;
  • 方案二适合需要保留扫描器状态的场景(比如不想每次切换步骤都重新初始化相机)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 23:15:16