flutter%20%E5%9C%A8%20Android%20%E7%AB%AF%E8%BF%9B%E8%A1%8C%E7%AE%80%E5%8D%95%E7%9A%84%E6%89%93%E5%BC%80%E5%89%8D%E5%90%8E%E7%9B%B8%E6%9C%BA%E9%A2%84%E8%A7%88%20%2F%20%E6%8B%8D%E7%85%A7%E4%BF%9D%E5%AD%98" name="Flutter%20%E5%AD%A6%E4%B9%A0%E4%B9%8B%E6%97%85%20%E4%B9%8B%20flutter%20%E5%9C%A8%20Android%20%E7%AB%AF%E8%BF%9B%E8%A1%8C%E7%AE%80%E5%8D%95%E7%9A%84%E6%89%93%E5%BC%80%E5%89%8D%E5%90%8E%E7%9B%B8%E6%9C%BA%E9%A2%84%E8%A7%88%20%2F%20%E6%8B%8D%E7%85%A7%E4%BF%9D%E5%AD%98">Flutter 学习之旅 之 flutter 在 Android 端进行简单的打开前后相机预览 / 拍照保存
目录
flutter%20%E5%9C%A8%20Android%20%E7%AB%AF%E8%BF%9B%E8%A1%8C%E7%AE%80%E5%8D%95%E7%9A%84%E6%89%93%E5%BC%80%E5%89%8D%E5%90%8E%E7%9B%B8%E6%9C%BA%E9%A2%84%E8%A7%88%20%2F%20%E6%8B%8D%E7%85%A7%E4%BF%9D%E5%AD%98-toc" name="tableOfContents" style="margin-left:0px">Flutter 学习之旅 之 flutter 在 Android 端进行简单的打开前后相机预览 / 拍照保存
一、简单介绍
二、简单介绍 camera
flutter-toc" name="tableOfContents" style="margin-left:40px">三、安装 camera
四、简单案例实现
五、关键代码
一、简单介绍
Flutter 是一款开源的 UI 软件开发工具包,由 Google 开发和维护。它允许开发者使用一套代码同时构建跨平台的应用程序,包括移动设备(iOS 和 Android)、Web 和桌面平台(Windows、macOS 和 Linux)。
Flutter 使用 Dart 编程语言,它可以将代码编译为 ARM 或 Intel 机器代码以及 JavaScript,从而实现快速的性能。Flutter 提供了一个丰富的预置小部件库,开发者可以根据自己的需求灵活地控制每个像素,从而创建自定义的、适应性强的设计,这些设计在任何屏幕上都能呈现出色的外观和感觉。
二、简单介绍 camera
网址:camera | Flutter package
一个用于iOS、Android和Web的Flutter插件,允许访问设备摄像头。
flutter" name="%E4%B8%89%E3%80%81%E5%AE%89%E8%A3%85%20webview_flutter">三、安装 camera
1、直接运行命令
使用 Flutter:flutter pub add camera
使用 Flutter 安装权限管理插件:flutter pub add permission_handler
使用 Flutter 安装图片保存插件:flutter pub add permission_handler
2、或者在 pubspec.yaml 添加
dependencies:camera: ^0.11.1permission_handler: ^11.4.0saver_gallery: ^4.0.1
四、简单案例实现
1、这里使用 Android Studio 进行创建 Flutter 项目
2、创建一个 application 的 Flutter 项目
3、工程创建后如下
4、添加权限
<uses-permission android:name="android.permission.CAMERA"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
6、连接设备,运行项目,简单效果如下
五、关键代码
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart' show getExternalStorageDirectory;
import 'package:path/path.dart' as path show join;
import 'package:permission_handler/permission_handler.dart';// 应用入口点
Future<void> main() async {// 确保 Flutter 的 WidgetsBinding 已初始化WidgetsFlutterBinding.ensureInitialized();// 请求存储权限await requestPermissions();// 获取设备上所有可用的摄像头列表final cameras = await availableCameras();runApp(MaterialApp(theme: ThemeData.dark(), // 使用暗色主题home: TakePictureScreen(cameras: cameras), // 传入摄像头列表),);
}// 请求存储权限的函数
Future<void> requestPermissions() async {// 检查存储权限的状态var status = await Permission.storage.status;if (!status.isGranted) {// 如果权限未开启,则请求权限await Permission.storage.request();}
}// TakePictureScreen 页面
class TakePictureScreen extends StatefulWidget {// 构造函数,传入摄像头列表const TakePictureScreen({super.key, required this.cameras});final List<CameraDescription> cameras;@overrideTakePictureScreenState createState() => TakePictureScreenState();
}// TakePictureScreen 的状态管理
class TakePictureScreenState extends State<TakePictureScreen> {late CameraController _controller; // 摄像头控制器late Future<void> _initializeControllerFuture; // 初始化摄像头的 Futureint _selectedCameraIndex = 0; // 当前选中的摄像头索引@overridevoid initState() {super.initState();// 初始化当前选中的摄像头_initializeCamera(widget.cameras[_selectedCameraIndex]);}// 初始化摄像头的函数void _initializeCamera(CameraDescription camera) {_controller = CameraController(camera, // 摄像头描述ResolutionPreset.medium, // 设置分辨率);_initializeControllerFuture = _controller.initialize(); // 初始化摄像头}// 切换摄像头的函数void _switchCamera() {setState(() {// 切换到下一个摄像头_selectedCameraIndex = (_selectedCameraIndex + 1) % widget.cameras.length;// 释放当前摄像头资源_controller.dispose();// 初始化新的摄像头_initializeCamera(widget.cameras[_selectedCameraIndex]);});}@overridevoid dispose() {// 释放摄像头资源_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Take a picture')), // 页面标题body: FutureBuilder<void>(future: _initializeControllerFuture, // 监听摄像头初始化的 Futurebuilder: (context, snapshot) {if (snapshot.connectionState == ConnectionState.done) {// 如果摄像头初始化完成,显示摄像头预览return CameraPreview(_controller);} else {// 如果摄像头初始化未完成,显示加载动画return const Center(child: CircularProgressIndicator());}},),floatingActionButton: Column(mainAxisAlignment: MainAxisAlignment.end,children: [// 拍照按钮FloatingActionButton(onPressed: () async {try {await _initializeControllerFuture; // 确保摄像头已初始化final image = await _controller.takePicture(); // 拍照print("Image path: ${image.path}");// 读取图片文件为字节数据final file = File(image.path);final imageBytes = await file.readAsBytes();print("Image bytes length: ${imageBytes.length}");// 手动保存图片到指定路径final saveResult = await saveImageManually(imageBytes);ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(saveResult)),);} catch (e) {print("Error taking picture: $e");}},child: const Icon(Icons.camera_alt), // 拍照图标),const SizedBox(height: 16),// 切换摄像头按钮FloatingActionButton(onPressed: _switchCamera, // 切换摄像头child: const Icon(Icons.switch_camera), // 切换摄像头图标),],),);}
}// 手动保存图片到指定路径的函数
Future<String> saveImageManually(Uint8List imageBytes) async {// 获取外部存储路径final directory = await getExternalStorageDirectory();if (directory == null) {throw Exception("Failed to get external storage directory.");}// 拼接目标路径final picturesDir = path.join(directory.path, "Pictures", "CameraApp");// 确保目标目录存在await Directory(picturesDir).create(recursive: true);// 生成文件名final fileName = "camera_image_${DateTime.now().millisecondsSinceEpoch}.jpg";final filePath = path.join(picturesDir, fileName);// 写入文件final file = File(filePath);await file.writeAsBytes(imageBytes);print("Image saved manually to: $filePath");return "Image saved to: $filePath";
}
代码说明
代码结构清晰:每个函数和逻辑块都有详细的注释,解释了其功能和实现方式。
关键点解释:
如何初始化摄像头。
如何切换摄像头。
如何保存图片到指定路径。
错误处理:在关键操作中添加了错误处理逻辑,并打印了错误信息。
用户交互:通过
SnackBar
提示用户图片保存成功或失败。