はじめに
以前、「撮影した写真や動画、カメラロールから画像や動画を取得する方法」で紹介したプラグインではカメラロールから画像や写真を選択する際は、1つしか選択できませんでした。
今回は複数選択できるプラグインを紹介しようと思います。
環境
- Flutter 2.0.6 Null-Safety
- multi_image_picker 4.8.0
実装方法
プラグインの最新バージョンを確認
下記のサイトにアクセスし、バージョンを確認します。
記事作成の時点では4.8.0が最新バージョンでした。
プラグインのインストール
pubspec.yamlのdependenciesに「multi_image_picker: ^4.8.0」を追記します。
または常に最新版を使う設定の「multi_image_picker: any」を追記します。
environment:
sdk: ">=2.12.0-0 <3.0.0"
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
multi_image_picker: any
その後、プロジェクト配下で「flutter pub get」コマンドを実行
よくわからない場合はAndroid Studioでpubspec.yamlファイルを開くと右上に「Pub get」ボタンがあるのでそれを押して下さい。
プラグインのインスールはここまでですが、プラグインを利用するにはアプリの設定を追加する必要があります。
アプリの設定を追加
アプリの設定を追加します。この設定をしないとカメラロールにアクセスした瞬間にアプリがクラッシュするので必ず対応してください。
iOS
iosフォルダを右クリックして[Flutter]→[Open iOS module in Xcode]を選択します。
Xcodeが開いたら、Runner/Runner/Info.plistに「Privacy – Photo Library Usage Description」の項目を追加し適切な文章を記入します。
ここに設定した文章はユーザーに表示されますので適切なものを設定して下さい。
Info.plistをテキストエディター等で開いた際は以下のような設定です。
<key>NSPhotoLibraryUsageDescription</key>
<string>なんか良さげな説明</string>
以上で、iOSの設定は終わりです。
Android
targetSdkVersionが29未満の場合は設定は不要です。
targetSdkVersionが29以上の場合はandroid/app/src/main/AndroidManifest.xmlを開きます。
<application>タグに「android:requestLegacyExternalStorage=”true”」を追加します。
以上で、Androidの設定も終了です。
サンプルコード
main.dart
import 'package:flutter/material.dart';
import 'package:multi_image_picker/multi_image_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Asset> images = <Asset>[];
String _error = 'No Error Dectected';
@override
void initState() {
super.initState();
}
Widget buildGridView() {
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
}
Future<void> loadAssets() async {
List<Asset> resultList = <Asset>[];
String error = 'No Error Detected';
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
} on Exception catch (e) {
error = e.toString();
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
_error = error;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
ElevatedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
),
);
}
}
結果
M1 MacだとAndroidエミュレーターが動作しなかったため、iOSでのみ確認を行いました。
無事動作しました!
さいごに
もし、ちゃんと実装する場合はプラグインを呼び出す前にパーミッション(権限)確認を毎回行ったほうが良いと思います。
コメント