Flutterで写真を撮るアプリを作りたいと思ったのでカメラ機能を入れてみました。
使ったプラグインはこちら。
まだAndroidでしか試してないけどもiOS/Androidで使えます。
Androidの場合minSdkVersion 21
です。
使い方
pubspec.yml
dependencies: flutter: sdk: flutter camera: ^0.4.2
これを追加してPackages getします。
camera.dart
カメラ機能を追加する画面をcamera.dartとして作ります。
class CameraView extends StatefulWidget { @override State createState() => CameraState(); } class CameraState extends State<CameraView> { @override Widget build(BuildContext context) { } }
まずはStatefulWidgetで画面を作ります。
class CameraState extends State<CameraView> { CameraController controller; Future<void> getCameras() async { cameras = await availableCameras(); controller = CameraController(cameras[0], ResolutionPreset.medium); } @override void initState() { super.initState(); getCameras().then((_) { controller.initialize().then((_) { if (!mounted) { return; } setState(() {}); }); }); } }
initState()
で使えるカメラを取得して、カメラコントローラーの初期化をします。
私が作りたいアプリの場合背面カメラの静止画だけでいいかなと思ったので1種類だけ使ってます。
機種に乗っていればフロントカメラやムービー撮影も使えるようです。
class CameraState extends State<CameraView> { @override Widget build(BuildContext context) { if (controller == null || !controller.value.isInitialized) { return Container(); } else { } } }
画面が起動した直後、またはカメラへのアクセス許可がされていない状態ではカメラプレビューを表示できないので、
コントローラーがnull
またはisInitialized
がfalse
の場合にはカメラプレビューではないWidgetを返します。
class CameraState extends State<CameraView> { @override Widget build(BuildContext context) { if (controller == null || !controller.value.isInitialized) { return Container(); } else { return AspectRatio( aspectRatio: controller.value.aspectRatio, child: CameraPreview(controller) ); } } }
AspectRatio
は縦横比を維持したまま、最大の大きさに広がってくれるWidgetです。
カメラcontrollerが縦横比を持っているのでそれを設定してあげるといい感じの大きさのプレビューが作れます。
CameraPreview(controller)
のところが実際のカメラプレビューになります。
class CameraState extends State<CameraView> { Future<String> takePicture() async { final Directory extDir = await getApplicationDocumentsDirectory(); final String dirPath = '${extDir.path}/Pictures/own_note'; await Directory(dirPath).create(recursive: true); final String filePath = '$dirPath/${timestamp()}.jpg'; if (controller.value.isTakingPicture) { // A capture is already pending, do nothing. return null; } try { await controller.takePicture(filePath); } on CameraException catch (e) { // エラー時の処理 return null; } return filePath; } @override Widget build(BuildContext context) { if (controller == null || !controller.value.isInitialized) { return Container(); } else { return Column( children: <Widget>[ AspectRatio( aspectRatio: controller.value.aspectRatio, child: CameraPreview(controller)), RaisedButton( child: Icon(Icons.camera), onPressed: () async { var filePath = await takePicture(); }, ), ] ); } } }
シャッターボタンを追加します。
ボタンWidgetのonPressed()
でtakePicture()
を呼び出します。
takePicture()
では、保存先のパスとファイル名を作り、画像を保存しています。
私が作りたいアプリの場合には、写真を撮った直後に同じ画面内にサムネイルを表示しつつ、
画像をサーバーへアップロードしているのでtakePicture()
が成功した場合にはファイルパスを返すようにしました。
色々装飾してますが、こんな感じになります。
ここを参考にしました。