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

如何为Flutter的flutter_camera_ml_vision添加闪光灯切换按钮

解决Flutter相机ML Vision运行时闪光灯切换冲突问题

我完全明白你遇到的困扰——用torch包切换闪光灯时触发CAMERA_IN_USE错误,这是因为flutter_camera_ml_vision已经占用了相机资源,第三方torch包再去操作同一个相机就会产生资源冲突。咱们换个思路,直接用flutter_camera_ml_vision依赖的camera包原生API来控制闪光灯,就能彻底解决这个问题。

问题根源

flutter_camera_ml_vision内部已经创建并维护了一个CameraController实例,而torch包会尝试直接访问相机硬件,两个工具同时操作同一个相机设备,自然会触发"相机被占用"的错误提示。

解决方案步骤

  1. 移除torch包依赖:既然要使用相机控制器原生API,这个第三方包就不需要了,从pubspec.yaml中删除它,同时删掉代码里的import 'package:torch/torch.dart';。
  2. 获取相机控制器实例:通过CameraMlVision的onCameraCreated回调拿到内部的CameraController,直接用它来控制闪光灯。
  3. 修改闪光灯切换逻辑:用CameraController的setFlashMode方法切换状态,支持FlashMode.torch(常亮)、FlashMode.off(关闭)等模式。
  4. 设置默认闪光灯状态:在相机初始化完成后,直接设置FlashMode.off,满足你"相机启动时闪光灯默认禁用"的需求。

修改后的完整代码

import 'package:firebase_ml_vision/firebase_ml_vision.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart';
import 'package:camera/camera.dart';

class ScanPage extends StatefulWidget {
  @override
  _ScanPageState createState() => _ScanPageState();
}

class _ScanPageState extends State<ScanPage> {
  bool resultSent = false;
  bool _isFlashOn = false;
  CameraController? _cameraController;

  @override
  void initState() {
    super.initState();
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  }

  @override
  void dispose() {
    _cameraController?.dispose();
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeRight,
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ]);
    super.dispose();
  }

  Future<void> _toggleFlash() async {
    if (_cameraController == null) return;

    try {
      final newFlashMode = _isFlashOn ? FlashMode.off : FlashMode.torch;
      await _cameraController!.setFlashMode(newFlashMode);
      setState(() {
        _isFlashOn = !_isFlashOn;
      });
    } catch (e) {
      print("切换闪光灯失败: $e");
      // 这里可以添加用户可见的错误提示,比如Toast或SnackBar
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _toggleFlash,
        child: Icon(_isFlashOn ? Icons.flash_off : Icons.flash_on),
        backgroundColor: Colors.green,
      ),
      body: SafeArea(
        child: SizedBox(
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height,
          child: CameraMlVision<List<Barcode>>(
            resolution: ResolutionPreset.medium,
            detector: FirebaseVision.instance.barcodeDetector().detectInImage,
            onCameraCreated: (controller) {
              // 保存相机控制器实例,后续用于闪光灯控制
              _cameraController = controller;
              // 初始化时将闪光灯设置为关闭状态
              controller.setFlashMode(FlashMode.off);
            },
            onResult: (List<Barcode> barcodes) {
              if (!mounted || resultSent || barcodes.isEmpty) {
                return;
              }
              resultSent = true;
              Navigator.of(context).pop<Barcode>(barcodes.first);
            },
          ),
        ),
      ),
    );
  }
}

关键代码说明

  • onCameraCreated回调:相机初始化完成后触发,我们在这里保存CameraController实例,后续所有闪光灯操作都通过它完成。
  • _toggleFlash方法:通过setFlashMode切换闪光灯状态,同时捕获异常(比如设备无闪光灯的情况),避免崩溃。
  • 默认闪光灯状态:在相机创建后立即设置FlashMode.off,完美匹配你需要的默认禁用需求。

这样修改后,闪光灯切换就不会再出现相机占用的错误了,因为我们通过同一个相机控制器操作闪光灯,完全避免了资源冲突问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:48:56