カメラを使って写真を撮る
多くのアプリでは、デバイスのカメラを操作する必要があります。
写真やビデオを撮ります。 Flutter が提供するのは、camera
プラグイン
この目的のために。のcamera
プラグインは、
利用可能なカメラ、特定のカメラからのプレビューを表示、
写真やビデオを撮ります。
このレシピでは、camera
プレビューを表示するプラグイン、
写真を撮り、次の手順で表示します。
- 必要な依存関係を追加します。
- 利用可能なカメラのリストを取得します。
- を作成して初期化する
CameraController
。 - 使う
CameraPreview
カメラのフィードを表示します。 - と一緒に写真を撮ります
CameraController
。 - で画像を表示します
Image
ウィジェット。
1. 必要な依存関係を追加します
このレシピを完成するには、アプリに 3 つの依存関係を追加する必要があります。
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;
CameraController
3. を作成して初期化します。カメラを入手したら、次の手順を実行します。
を作成して初期化するCameraController
。
このプロセスにより、次への接続が確立されます。
カメラを制御できるデバイスのカメラ
カメラのフィードのプレビューを表示します。
- を作成します
StatefulWidget
仲間と一緒にState
クラス。 - に変数を追加します。
State
を格納するクラスCameraController
。 - に変数を追加します。
State
を格納するクラスFuture
から戻ってきましたCameraController.initialize()
。 - でコントローラーを作成して初期化します。
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();
}
}
CameraPreview
カメラのフィードを表示するには
4.次に、CameraPreview
のウィジェットcamera
にパッケージ化する
カメラのフィードのプレビューを表示します。
使う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());
}
},
)
CameraController
5. で写真を撮ります。使用できますCameraController
を使用して写真を撮るにはtakePicture()
メソッド。XFile
、
シンプルなクロスプラットフォームFile
抽象化。
Android と IOS の両方で、新しいイメージは次の場所に保存されます。
それぞれのキャッシュディレクトリ、
そしてそのpath
その場所に返されるのは、XFile
。
この例では、FloatingActionButton
それは写真を撮ります
を使用してCameraController
ユーザーがボタンをタップしたとき。
写真を撮るには 2 つの手順が必要です。
- カメラが初期化されていることを確認してください。
- コントローラーを使用して写真を撮り、コントローラーが結果を返すことを確認します。
Future<XFile>
。
これらの操作を 1 つにラップすることをお勧めします。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),
)
Image
ウィジェット
6. 画像を表示します。写真の撮影に成功すると、保存した写真を表示できます
を使用してImage
ウィジェット。この場合、画像はファイルとして保存されます。
デバイス。
したがって、次のものを提供する必要があります。File
にImage.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 (!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)),
);
}
}