环境
Flutter 3.29
macOS Sequoia 15.4.1
Xcode 16.3
集成
- 创建一个带有 State 类的 StatefulWidget 组件
- 添加一个变量到 State 类来存放 CameraController
- 添加另外一个变量到 State 类中来存放 CameraController.initialize() 返回的 Future
- 在 initState() 方法中创建并初始化控制器
- 在 dispose() 方法中销毁控制器
创建并初始化 CameraController
新建take_photo.dart文件,输入stf快捷创建一个有状态的Widget,命名为TakePictureScreen
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class TakePictureScreen extends StatefulWidget { const TakePictureScreen({super.key, required this.cameras}); final List<CameraDescription> cameras;
@override TakePictureScreenState createState() => TakePictureScreenState(); }
class TakePictureScreenState extends State<TakePictureScreen> { late CameraController _controller; late Future<void> _initializeControllerFuture; }
|
在 initState 方法中创建并初始化控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class TakePictureScreenState extends State<TakePictureScreen> {
int frontCamera = 0; ... @override void initState() { super.initState(); _controller = CameraController( widget.cameras[frontCamera], ResolutionPreset.medium, ); _initializeControllerFuture = _controller.initialize(); } ...
|
预览
使用CameraPreview类实现相机的预览
1 2 3 4 5 6 7 8 9 10 11 12 13
| FutureBuilder<void>( future: _initializeControllerFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return CameraPreview(_controller); } else { return const Center(child: CircularProgressIndicator()); } }, ),
|
使用 CameraController 拍照
使用CameraController的takePicture()方法实现拍照功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class TakePictureScreenState extends State<TakePictureScreen> { String photoPath = ""; ... Widget build(BuildContext context) { ... onPressed: () async { try { await _initializeControllerFuture;
final image = await _controller.takePicture(); if (!context.mounted) return; setState(() { photoPath = image.path; }); } catch (e) { } }, } }
|
发送消息到原生方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| - (void)captureToFileWithCompletion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion { AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; ... __weak typeof(self) weakSelf = self; FLTSavePhotoDelegate *savePhotoDelegate = [[FLTSavePhotoDelegate alloc] initWithPath:path ioQueue:self.photoIOQueue completionHandler:^(NSString *_Nullable path, NSError *_Nullable error) { typeof(self) strongSelf = weakSelf; if (!strongSelf) return; dispatch_async(strongSelf.captureSessionQueue, ^{ typeof(self) strongSelf = weakSelf; if (!strongSelf) return; [strongSelf.inProgressSavePhotoDelegates removeObjectForKey:@(settings.uniqueID)]; });
if (error) { completion(nil, FlutterErrorFromNSError(error)); } else { NSAssert(path, @"Path must not be nil if no error."); completion(path, nil); } }]; ... [self.capturePhotoOutput capturePhotoWithSettings:settings delegate:savePhotoDelegate]; }
|
在 dispose 方法中销毁控制器
1 2 3 4 5
| @override void dispose() { _controller.dispose(); super.dispose(); }
|
开启闪光灯
使用CameraController对象的setFlashMode方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class TakePictureScreenState extends State<TakePictureScreen> { FlashMode _flashMode = FlashMode.always; ... onPressed: () { setState(() { if (_flashMode == FlashMode.always) { _flashMode = FlashMode.auto; } else if (_flashMode == FlashMode.auto) { _flashMode = FlashMode.off; } else if (_flashMode == FlashMode.off) { _flashMode = FlashMode.always; } _controller.setFlashMode(_flashMode); }); }; }
|

切换摄像头
通过更新CameraController对象的description参数来切换摄像头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| onPressed: () async { if (frontCamera == 1) { _controller = CameraController( widget.cameras[0], ResolutionPreset.medium, ); _controller.initialize().then((_) { if (mounted) { frontCamera = 0; setState(() {}); } }); } else { _controller = CameraController( widget.cameras[1], ResolutionPreset.medium, ); _controller.initialize().then((_) { if (mounted) { frontCamera = 1; setState(() {}); } }); } },
|
设置焦距
使用CameraController对象的setZoomLevel方法设置焦距
1 2 3 4 5 6 7 8
| ... onPressed: () { setState(() { _controller.setZoomLevel(1); _isMinZoomLevel = true; minZoomLevelDesc = "0.5x"; }); },
|
拍照后显示缩略图
使用Align设置缩略图靠左
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| SizedBox( width: MediaQuery.of(context).size.width, child: Stack( fit: StackFit.loose, children: [ Align( alignment: Alignment(-0.8, 0), child: SizedBox( width: 60, height: 60, child: photoPath.isEmpty ? Container() : Image.file(File(photoPath)), ), ),
|

其它
装修结束,闲居在家

参考
- 使用 Camera 插件实现拍照功能
- Flutter——最详细Stack(堆叠布局)使用教程
- flutter 调用摄像头,前后镜头切换