使用相机拍照
许多应用都需要使用设备的相机来拍摄照片和视频。Flutter 提供了 camera
插件来实现此目的。camera
插件提供工具来获取可用相机的列表,显示来自特定相机的预览,以及拍摄照片或视频。
此示例演示了如何使用 camera
插件显示预览、拍照以及使用以下步骤显示照片:
- 添加所需的依赖项。
- 获取可用相机的列表。
- 创建和初始化
CameraController
。 - 使用
CameraPreview
显示相机的馈送。 - 使用
CameraController
拍照。 - 使用
Image
小部件显示图片。
1. 添加所需的依赖项
#要完成此示例,您需要向您的应用添加三个依赖项:
camera
- 提供用于处理设备上相机的工具。
path_provider
- 查找存储图像的正确路径。
path
- 创建在任何平台上都能工作的路径。
要添加这些包作为依赖项,请运行 flutter pub add
:
flutter pub add camera path_provider path
2. 获取可用相机的列表
#接下来,使用 camera
插件获取可用相机的列表。
// 确保初始化插件服务,以便在 `runApp()` 之前可以调用 `availableCameras()`
WidgetsFlutterBinding.ensureInitialized();
// 获取设备上可用相机的列表。
final cameras = await availableCameras();
// 从可用相机列表中获取特定相机。
final firstCamera = cameras.first;
3. 创建和初始化 CameraController
#获得相机后,请按照以下步骤创建和初始化 CameraController
。此过程建立与设备相机的连接,允许您控制相机并显示相机馈送的预览。
- 创建一个带有配套
State
类的StatefulWidget
。 - 向
State
类添加一个变量来存储CameraController
。 - 向
State
类添加一个变量来存储CameraController.initialize()
返回的Future
。 - 在
initState()
方法中创建和初始化控制器。 - 在
dispose()
方法中释放控制器。
// 允许用户使用给定相机拍照的屏幕。
class TakePictureScreen extends StatefulWidget {
const TakePictureScreen({
super.key,
required this.camera,
});
final CameraDescription camera;
@override
TakePictureScreenState createState() => TakePictureScreenState();
}
class TakePictureScreenState extends State<TakePictureScreen> {
late CameraController _controller;
late Future<void> _initializeControllerFuture;
@override
void initState() {
super.initState();
// 要显示来自相机的当前输出,请创建一个 CameraController。
_controller = CameraController(
// 从可用相机列表中获取特定相机。
widget.camera,
// 定义要使用的分辨率。
ResolutionPreset.medium,
);
// 接下来,初始化控制器。这将返回一个 Future。
_initializeControllerFuture = _controller.initialize();
}
@override
void dispose() {
// 在窗口小部件被释放时释放控制器。
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// 在接下来的步骤中填写此内容。
return Container();
}
}
4. 使用 CameraPreview
显示相机的馈送
#接下来,使用 camera
包中的 CameraPreview
小部件来显示相机馈送的预览。
为此目的,请使用 FutureBuilder
。
// 在显示相机预览之前,必须等到控制器初始化完成。使用 FutureBuilder 显示加载微调器,直到控制器完成初始化。
FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// 如果 Future 已完成,则显示预览。
return CameraPreview(_controller);
} else {
// 否则,显示加载指示器。
return const Center(child: CircularProgressIndicator());
}
},
)
5. 使用 CameraController
拍照
#您可以使用 CameraController
通过 takePicture()
方法拍照,该方法返回一个 XFile
,这是一个跨平台的简化 File
抽象。在 Android 和 IOS 上,新图像都存储在其各自的缓存目录中,该位置的 path
将在 XFile
中返回。
在此示例中,创建一个 FloatingActionButton
,当用户点击按钮时,该按钮使用 CameraController
拍照。
拍照需要两个步骤:
- 确保相机已初始化。
- 使用控制器拍照并确保它返回一个
Future<XFile>
。
最好将这些操作包装在 try / catch
块中,以处理可能发生的任何错误。
FloatingActionButton(
// 提供一个 onPressed 回调。
onPressed: () async {
// 在 try / catch 块中拍照。如果出现任何错误,则捕获错误。
try {
// 确保相机已初始化。
await _initializeControllerFuture;
// 尝试拍照,然后获取保存图像文件的路径。
final image = await _controller.takePicture();
} catch (e) {
// 如果发生错误,则将错误记录到控制台。
print(e);
}
},
child: const Icon(Icons.camera_alt),
)
6. 使用 Image
小部件显示图片
#如果成功拍照,则可以使用 Image
小部件显示保存的图片。在这种情况下,图片作为文件存储在设备上。
因此,必须向 Image.file
构造函数提供一个 File
。您可以通过传递上一步中创建的路径来创建 File
类的实例。
Image.file(File('path/to/my/picture.png'));
##完整示例
import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
// 确保初始化插件服务,以便在 `runApp()` 之前可以调用 `availableCameras()`
WidgetsFlutterBinding.ensureInitialized();
// 获取设备上可用相机的列表。
final cameras = await availableCameras();
// 从可用相机列表中获取特定相机。
final firstCamera = cameras.first;
runApp(
MaterialApp(
theme: ThemeData.dark(),
home: TakePictureScreen(
// 将适当的相机传递给 TakePictureScreen 小部件。
camera: firstCamera,
),
),
);
}
// 允许用户使用给定相机拍照的屏幕。
class TakePictureScreen extends StatefulWidget {
const TakePictureScreen({
super.key,
required this.camera,
});
final CameraDescription camera;
@override
TakePictureScreenState createState() => TakePictureScreenState();
}
class TakePictureScreenState extends State<TakePictureScreen> {
late CameraController _controller;
late Future<void> _initializeControllerFuture;
@override
void initState() {
super.initState();
// 要显示来自相机的当前输出,请创建一个 CameraController。
_controller = CameraController(
// 从可用相机列表中获取特定相机。
widget.camera,
// 定义要使用的分辨率。
ResolutionPreset.medium,
);
// 接下来,初始化控制器。这将返回一个 Future。
_initializeControllerFuture = _controller.initialize();
}
@override
void dispose() {
// 在窗口小部件被释放时释放控制器。
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Take a picture')),
// 在显示相机预览之前,必须等到控制器初始化完成。使用 FutureBuilder 显示加载微调器,直到控制器完成初始化。
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// 如果 Future 已完成,则显示预览。
return CameraPreview(_controller);
} else {
// 否则,显示加载指示器。
return const Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
// 提供一个 onPressed 回调。
onPressed: () async {
// 在 try / catch 块中拍照。如果出现任何错误,则捕获错误。
try {
// 确保相机已初始化。
await _initializeControllerFuture;
// 尝试拍照并获取保存文件的 `image`。
final image = await _controller.takePicture();
if (!context.mounted) return;
// 如果拍摄了照片,则在新屏幕上显示它。
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(
// 将自动生成的路径传递给 DisplayPictureScreen 小部件。
imagePath: image.path,
),
),
);
} catch (e) {
// 如果发生错误,则将错误记录到控制台。
print(e);
}
},
child: const Icon(Icons.camera_alt),
),
);
}
}
// 显示用户拍摄的照片的小部件。
class DisplayPictureScreen extends StatelessWidget {
final String imagePath;
const DisplayPictureScreen({super.key, required this.imagePath});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Display the Picture')),
// 图片作为文件存储在设备上。使用带有给定路径的 `Image.file` 构造函数来显示图片。
body: Image.file(File(imagePath)),
);
}
}
除非另有说明,否则本网站上的文档反映的是 Flutter 的最新稳定版本。页面最后更新于 2025-01-30。 查看源代码 或 报告问题。