この記事はこちら↓の続きです。
image_picker を使うと Flutter アプリで写真撮影を簡単に実装できて非常に便利なのですが、個人的には
- 1 枚写真を撮影するごとに元の画面に戻らないといけない(あらためて「撮影」などのリンクをタップしてカメラを起動する)のが面倒
と感じることがあります。
(単純にpickImage()
の呼び出しをループさせるだけだと、2 回目の呼び出しで「呼び出し元の画面(ウィジェット)がない」みたいなことを言われて怒られます。)
そのため、写真の保存後に引き続き撮影を続ける方法を考えてみました(注:手抜きです)。
準備
基本的には前回の記事のとおりですが、現時点で使用するライブラリのバージョンが少し進んでいますのでそれに合わせます。
pubspec.yaml(関連部分)
image_picker: ^0.8.4+4
cross_file: ^0.3.2
image_gallery_saver: ^1.7.1
path_provider: ^2.0.6
iOS の場合のInfo.plist
は変更なしです。
Info.plist(image_picker関連)
<key>NSPhotoLibraryUsageDescription</key>
<string>This app requires to access your photo library</string>
<key>NSCameraUsageDescription</key>
<string>This app requires to add file to your camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires to add file to your photo library your microphone</string>
Info.plist(path_providerファイル保存先関連)
<key>UISupportsDocumentBrowser</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
コード例
パッケージインポート
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:cross_file/cross_file.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
写真撮影・保存(それぞれ 1 回分)は前の記事と同じです。
写真撮影
final ImagePicker _picker = ImagePicker();
(中略)
Future<XFile?> _takePhoto() {
return _picker.pickImage(
source: ImageSource.camera,
maxWidth: 1600,
maxHeight: 1600,
imageQuality: 85);
}
写真を保存する
Future<String> _savePhoto(XFile photo) async {
final Uint8List buffer = await photo.readAsBytes();
final String savePath = '$_imagePath/${photo.name}';
final File saveFile = File(savePath);
saveFile.writeAsBytesSync(buffer, flush: true, mode: FileMode.write);
// 画像ギャラリーにも保存(オプション)
await ImageGallerySaver.saveImage(buffer, name: photo.name);
return saveFile.path;
}
写真撮影→保存の呼び出し元を変更します。
呼び出し元
Timer? _timer;
(中略)
String photoPath = '';
final XFile? photo = await _takePhoto();
while (photo != null) {
// キャンセルするまで続けて撮影する
photoPath = await _savePhoto(photo);
File file = File(photoPath);
await showDialog(
context: context,
builder: (BuildContext builderContext) {
_timer = Timer(const Duration(seconds: 1), () async {
photo = await _takePhoto();
Navigator.of(context).pop();
});
return AlertDialog(
actionsAlignment: MainAxisAlignment.center,
content: SingleChildScrollView(
child: Image.file(file, width: 240.0, fit: BoxFit.scaleDown),
),
);
}).then((val) {
if (_timer!.isActive) {
_timer!.cancel();
}
});
}
Duration
の時間や表示する写真のサイズなどは好みに合わせて調整します。
写真撮影して「保存」(Use Photo)を選ぶとDuration
の時間アラートダイアログで撮影した写真を表示し、その後自動的に写真撮影画面に遷移します。
※わたしの自作アプリではここ↓で使っています。