Flutter 学习之旅 之 flutter 在 Android 端进行简单的打开前后相机预览 / 拍照保存

ops/2025/3/2 0:39:43/

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"/>

5、编写代码实现打开相机,预览,拍照功能

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";
}

代码说明

  1. 代码结构清晰:每个函数和逻辑块都有详细的注释,解释了其功能和实现方式。

  2. 关键点解释

    • 如何初始化摄像头。

    • 如何切换摄像头。

    • 如何保存图片到指定路径。

  3. 错误处理:在关键操作中添加了错误处理逻辑,并打印了错误信息。

  4. 用户交互:通过 SnackBar 提示用户图片保存成功或失败。


http://www.ppmy.cn/ops/162367.html

相关文章

网络安全 | 5G网络安全:未来无线通信的风险与对策

网络安全 | 5G网络安全:未来无线通信的风险与对策 一、前言二、5G 网络的技术特点2.1 超高速率与低延迟2.2 大容量连接与网络切片三、5G 网络面临的安全风险3.1 网络架构安全风险3.2 设备终端安全风险3.3 应用场景安全风险3.4 用户隐私安全风险四、5G 网络安全对策4.1 强化网络…

Milvus高性能向量数据库与大模型结合

Milvus | 高性能向量数据库&#xff0c;为规模而构建Milvus 是一个为 GenAI 应用构建的开源向量数据库。使用 pip 安装&#xff0c;执行高速搜索&#xff0c;并扩展到数十亿个向量。https://milvus.io/zh Milvus 是什么&#xff1f; Milvus 是一种高性能、高扩展性的向量数据…

游戏引擎学习第127天

仓库:https://gitee.com/mrxiao_com/2d_game_3 为本周设定阶段 我们目前的渲染器已经实现了令人惊讶的优化&#xff0c;经过过去两周的优化工作后&#xff0c;渲染器在1920x1080分辨率下稳定地运行在60帧每秒。这个结果是意料之外的&#xff0c;因为我们没有预计会达到这样的…

模拟器游戏多开为什么需要单窗口单IP

模拟器游戏多开时采用单窗口单IP的主要目的是为了规避游戏运营商的反作弊检测机制&#xff0c;降低账号关联风险&#xff0c;并确保多开行为的隐蔽性。以下是具体原因&#xff1a; 1. 避免账号关联封禁 游戏公司通常会通过IP地址、设备指纹&#xff08;如MAC地址、硬件ID&…

SpringBoot集成Flink-CDC,实现对数据库数据的监听

一、什么是 CDC &#xff1f; CDC 是Change Data Capture&#xff08;变更数据获取&#xff09;的简称。 核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数据表的插入、 更新以及删除等&#xff09;&#xff0c;将这些变更按发生的顺序完整记录下来&…

多通道数据采集和信号生成的模块化仪器如何重构飞机电子可靠性测试体系?

飞机的核心电子系统包括发电与配电系统&#xff0c;飞机内部所有设备和系统之间的内部数据通信系统&#xff0c;以及用于外部通信的射频设备。其他所有航空电子元件都依赖这些关键总线进行电力传输或数据通信。在本文中&#xff0c;我们将了解模块化仪器&#xff08;无论是PCIe…

SQL 注入漏洞原理以及修复方法

漏洞名称 &#xff1a;SQL注入 、SQL盲注 漏洞描述&#xff1a;所谓SQL注入&#xff0c;就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串&#xff0c;最终达到欺骗服务器执行恶意的SQL命令。具体来说&#xff0c;它是利用现有应用程序&#xff0c;将&…

神经网络中的Adam

Adam&#xff08;Adaptive Moment Estimation&#xff09;是一种广泛使用的优化算法&#xff0c;结合了RMSprop和动量&#xff08;Momentum&#xff09;的优点。它通过计算梯度的一阶矩估计&#xff08;mean&#xff09;和二阶矩估计&#xff08;uncentered variance&#xff0…