今回は、Flutterで画像を表示する方法について紹介したいと思います。
パッケージを使うことで、簡単に実装できます。
パッケージに感謝。
目次
image_pickerを使おう
使用するflutterのパッケージはこれ↓
このimage_pickerというパッケージを使用すれば、
・カメラから
・アルバムから
簡単に画像をアップロードすることができます。

上の写真のように下側からボトムバーが出てきて、カメラからか、アルバムからか選択する場面がよくありますよね。
このような感じで実装できるわけです。
以下では、image_pickerの具体的な実装方法を説明します。
image pickerの実装方法
では、パッケージのインストールを行いましょう。
image_pickerをインストール
慣れている人なら秒で終わりますね。
1.pubspec.yaml に以下を追加。
dependencies: image_picker: ^0.6.7+4
2.コマンドラインでflutter pub get
ちゃんとプロジェクトのディレクトリで行ってください。
3.import ‘package:image_picker/image_picker.dart’;をコードに追加。
お決まりの3ステップです。
ios、androidでの設定
PackageのReadmeによると、
iosの場合は、
Add the following keys to your Info.plist file, located in
<project root>/ios/Runner/Info.plist
:
NSPhotoLibraryUsageDescription
– describe why your app needs permission for the photo library. This is called Privacy – Photo Library Usage Description in the visual editor.
NSCameraUsageDescription
– describe why your app needs access to the camera. This is called Privacy – Camera Usage Description in the visual editor.
NSMicrophoneUsageDescription
– describe why your app needs access to the microphone, if you intend to record videos. This is called Privacy – Microphone Usage Description in the visual editor.
と書いてあります。
つまり、プロジェクトの中のios/Runner/info.plistの中に、
<key>NSMicrophoneUsageDescription</key>
<string>画像のアップロードのため</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>ギャラリーからの画像のアップロードのため</string>
<key>NSCameraUsageDescription</key>
<string>カメラでの画像のアップロードのため</string>
この3つを追加すればOKです。
describe why your app needs…の説明にもあるように、用途を記述しておきましょう。
Androidの場合は、
API 29+
No configuration required – the plugin should work out of the box.
API < 29
Add
android:requestLegacyExternalStorage="true"
as an attribute to the<application>
tag in AndroidManifest.xml. The attribute isfalse
by default on apps targeting Android Q.
と書いてあります。
APIレベルが29以上なら、何も必要なし。
29よりも下ならば、プロジェクト内のandroid/app/src/main/AndroidManifest.xmlの中の<application>タグの中に、
android:requestLegacyExternalStorage=”true”
を追加しましょう。
ちなみに、APIレベルは、android/app/build.gradleで確認できます。
minSdkVersion 16
targetSdkVersion 29
こんな感じの記述があると思います。
僕の場合は、APIレベルが29なので、何も設定は必要なかったです。
ここまでやれば、ようやく使用可能になります。
image_pickerを用いたコピペ用コード
僕の場合は以下のようなコードを書いて、プロジェクト内で使い回しています。
import 'dart:io';
import 'package:flutter_native_image/flutter_native_image.dart';
import 'package:image_picker/image_picker.dart';
//カメラ、ギャラリーからのアップロードはここでやる
class ImageUpload {
ImageUpload(this.source, {this.quality = 50});
final ImageSource source;
final int quality;
Future<File> getImageFromDevice() async {
// 撮影/選択したFileが返ってくる
final imageFile = await ImagePicker().getImage(source: source);
// Androidで撮影せずに閉じた場合はnullになる
if (imageFile == null) {
return null;
}
//画像を圧縮
final File compressedFile = await FlutterNativeImage.compressImage(
imageFile.path,
quality: quality);
return compressedFile;
}
}
ちなみに画像のアップロードと、画像の圧縮を一気にやっています。
写真のアップロードを数箇所で行うプロジェクトであれば、このコードを使い回すのが良いでしょう。
サンプルコード

uploadボタンを押すと、ボトムシートがでてきて、選択をすると写真をアップロードできるサンプルコードです。
ちなみにシミュレータだと、カメラで撮影はうまくいかないので、実機で試してください。
サンプル全体のコードは以下の通りです。
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_native_image/flutter_native_image.dart';
import 'package:image_picker/image_picker.dart';
class ImageUploadScreen extends StatefulWidget {
@override
_ImageUploadScreenState createState() => _ImageUploadScreenState();
}
class _ImageUploadScreenState extends State<ImageUploadScreen> {
File file;
Future<int> showCupertinoBottomBar() {
//選択するためのボトムシートを表示
return showCupertinoModalPopup<int>(
context: context,
builder: (BuildContext context) {
return CupertinoActionSheet(
message: Text('写真をアップロードしますか?'),
actions: <Widget>[
CupertinoActionSheetAction(
child: Text(
'カメラで撮影',
),
onPressed: () {
Navigator.pop(context, 0);
},
),
CupertinoActionSheetAction(
child: Text(
'アルバムから選択',
),
onPressed: () {
Navigator.pop(context, 1);
},
),
],
cancelButton: CupertinoActionSheetAction(
child: const Text('キャンセル'),
onPressed: () {
Navigator.pop(context, 2);
},
isDefaultAction: true,
),
);
});
}
void showBottomSheet() async {
//ボトムシートから受け取った値によって操作を変える
final result = await showCupertinoBottomBar();
File imageFile;
if (result == 0) {
imageFile = await ImageUpload(ImageSource.camera).getImageFromDevice();
} else if (result == 1) {
imageFile = await ImageUpload(ImageSource.gallery).getImageFromDevice();
}
setState(() {
file = imageFile;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Picker'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (file != null)
Container(
height: 300,
width: 300,
child: Image.file(file),
),
RaisedButton(
child: Text('upload'),
onPressed: () {
showBottomSheet();
},
)
],
),
),
);
}
}
//カメラ、ギャラリーからのアップロードはここでやる
class ImageUpload {
ImageUpload(this.source, {this.quality = 50});
final ImageSource source;
final int quality;
Future<File> getImageFromDevice() async {
// 撮影/選択したFileが返ってくる
final imageFile = await ImagePicker().getImage(source: source);
// Androidで撮影せずに閉じた場合はnullになる
if (imageFile == null) {
return null;
}
//画像を圧縮
final File compressedFile = await FlutterNativeImage.compressImage(
imageFile.path,
quality: quality);
return compressedFile;
}
}
これをデフォルトのMyAppクラスのhomeに入れていただければ動きます。

こんな感じでイメージをアップロードできます。
ちなみに、画像の圧縮についてはこちらで詳しく説明しています。

また、画像をfirebase storageに保存する方法はこちらから。

image_pickerがクラッシュする場合がある
パッケージのインストール、ios、androidの設定が終わった後に、そのまま動かそうとしたら、クラッシュしました。。。
僕の場合は、一旦AndroidStudioを閉じて、その後、Podfile.lockを消してから、pod installで入れ直したら、動きました。
まとめると、
・AndroidStudioを閉じる
・flutter clean
・Podfile.lockを消す
・iosのなかで、pod install
これをやったら動きました。
上記のios、androidの設定を行っていない場合は、間違いなくcrashですね。。
まとめ
いかがでしたか?
image_pickerは他のパケージの導入よりも、少し面倒ですが、一度実装できてしまえばこっちのものです。
crashする問題も少し面倒ですね。。
どのプロジェクトでも使用するレベルのパッケージなので、一度、しっかりと実装できるようにしてしまいましょう。
この記事が参考になれば幸いです。