如何为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包会尝试直接访问相机硬件,两个工具同时操作同一个相机设备,自然会触发"相机被占用"的错误提示。
解决方案步骤
- 移除
torch包依赖:既然要使用相机控制器原生API,这个第三方包就不需要了,从pubspec.yaml中删除它,同时删掉代码里的import 'package:torch/torch.dart';。 - 获取相机控制器实例:通过
CameraMlVision的onCameraCreated回调拿到内部的CameraController,直接用它来控制闪光灯。 - 修改闪光灯切换逻辑:用
CameraController的setFlashMode方法切换状态,支持FlashMode.torch(常亮)、FlashMode.off(关闭)等模式。 - 设置默认闪光灯状态:在相机初始化完成后,直接设置
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
相关产品推荐
相关产品推荐

