使用相機拍照
許多應用程式需要使用裝置的相機來拍照和錄影。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
外掛程式取得可用相機的列表。
// Ensure that plugin services are initialized so that `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();
// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();
// Get a specific camera from the list of available cameras.
final firstCamera = cameras.first;
3. 建立並初始化 CameraController
#取得相機後,使用下列步驟來建立並初始化 CameraController
。此過程會建立與裝置相機的連線,讓您可以控制相機並顯示相機畫面的預覽。
- 建立具有伴隨
State
類別的StatefulWidget
。 - 將變數新增至
State
類別以儲存CameraController
。 - 將變數新增至
State
類別以儲存從CameraController.initialize()
傳回的Future
。 - 在
initState()
方法中建立並初始化控制器。 - 在
dispose()
方法中處置控制器。
// A screen that allows users to take a picture using a given camera.
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();
// To display the current output from the Camera,
// create a CameraController.
_controller = CameraController(
// Get a specific camera from the list of available cameras.
widget.camera,
// Define the resolution to use.
ResolutionPreset.medium,
);
// Next, initialize the controller. This returns a Future.
_initializeControllerFuture = _controller.initialize();
}
@override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// Fill this out in the next steps.
return Container();
}
}
4. 使用 CameraPreview
顯示相機的畫面
#接下來,使用 camera
套件中的 CameraPreview
小工具來顯示相機畫面的預覽。
使用 FutureBuilder
正是為了這個目的。
// You must wait until the controller is initialized before displaying the
// camera preview. Use a FutureBuilder to display a loading spinner until the
// controller has finished initializing.
FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview.
return CameraPreview(_controller);
} else {
// Otherwise, display a loading indicator.
return const Center(child: CircularProgressIndicator());
}
},
)
5. 使用 CameraController
拍照
#您可以使用 CameraController
的 takePicture()
方法來拍照,該方法會傳回 XFile
,這是一個跨平台的簡化 File
抽象。在 Android 和 IOS 上,新影像會儲存在各自的快取目錄中,而該位置的 path
會在 XFile
中傳回。
在本範例中,建立一個 FloatingActionButton
,當使用者點擊按鈕時,該按鈕會使用 CameraController
拍照。
拍照需要 2 個步驟
- 確保相機已初始化。
- 使用控制器拍照並確保它傳回
Future<XFile>
。
最好將這些操作包裝在 try / catch
區塊中,以便處理可能發生的任何錯誤。
FloatingActionButton(
// Provide an onPressed callback.
onPressed: () async {
// Take the Picture in a try / catch block. If anything goes wrong,
// catch the error.
try {
// Ensure that the camera is initialized.
await _initializeControllerFuture;
// Attempt to take a picture and then get the location
// where the image file is saved.
final image = await _controller.takePicture();
} catch (e) {
// If an error occurs, log the error to the console.
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 {
// Ensure that plugin services are initialized so that `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();
// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();
// Get a specific camera from the list of available cameras.
final firstCamera = cameras.first;
runApp(
MaterialApp(
theme: ThemeData.dark(),
home: TakePictureScreen(
// Pass the appropriate camera to the TakePictureScreen widget.
camera: firstCamera,
),
),
);
}
// A screen that allows users to take a picture using a given camera.
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();
// To display the current output from the Camera,
// create a CameraController.
_controller = CameraController(
// Get a specific camera from the list of available cameras.
widget.camera,
// Define the resolution to use.
ResolutionPreset.medium,
);
// Next, initialize the controller. This returns a Future.
_initializeControllerFuture = _controller.initialize();
}
@override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Take a picture')),
// You must wait until the controller is initialized before displaying the
// camera preview. Use a FutureBuilder to display a loading spinner until the
// controller has finished initializing.
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview.
return CameraPreview(_controller);
} else {
// Otherwise, display a loading indicator.
return const Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
// Provide an onPressed callback.
onPressed: () async {
// Take the Picture in a try / catch block. If anything goes wrong,
// catch the error.
try {
// Ensure that the camera is initialized.
await _initializeControllerFuture;
// Attempt to take a picture and get the file `image`
// where it was saved.
final image = await _controller.takePicture();
if (!context.mounted) return;
// If the picture was taken, display it on a new screen.
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(
// Pass the automatically generated path to
// the DisplayPictureScreen widget.
imagePath: image.path,
),
),
);
} catch (e) {
// If an error occurs, log the error to the console.
print(e);
}
},
child: const Icon(Icons.camera_alt),
),
);
}
}
// A widget that displays the picture taken by the user.
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')),
// The image is stored as a file on the device. Use the `Image.file`
// constructor with the given path to display the image.
body: Image.file(File(imagePath)),
);
}
}
除非另有說明,否則本網站上的文件反映了 Flutter 的最新穩定版本。頁面最後更新於 2024-06-24。 檢視原始碼 或 回報問題。