メインコンテンツまでスキップ

Flutter ImagePicker - Pick or Capture Images and Video

In this article, we will focus on ImagePicker widget, which is a built-in widget in Flutter that allows the user to select an image from the device's gallery or take a new picture using the camera.

Steps to use ImagePicker widget

Step 1: Add ImagePicker plugin to the project

The first step to use the ImagePicker widget is to add the ImagePicker plugin to the project. To add the plugin, you need to add the following dependency in the pubspec.yaml file:

dependencies:
image_picker: ^0.8.3+2

After adding the dependency, run the following command in the terminal:

flutter pub get

Step 2: Import the required libraries

After adding the ImagePicker plugin to the project, you need to import the required libraries in the Dart file where you want to use the ImagePicker widget. You can import the libraries as follows:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

Step 3: Add the ImagePicker widget to the UI

Once you have imported the required libraries, you can add the ImagePicker widget to the UI as follows:

class MyHomePage extends StatefulWidget {

_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
File? _image;

Future<void> _getImage() async {
final picker = ImagePicker();
final pickedImage = await picker.getImage(source: ImageSource.gallery);

setState(() {
if (pickedImage != null) {
_image = File(pickedImage.path);
} else {
print('No image selected.');
}
});
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Picker Demo'),
),
body: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image!),
),
floatingActionButton: FloatingActionButton(
onPressed: _getImage,
tooltip: 'Pick Image',
child: Icon(Icons.add_a_photo),
),
);
}
}

In the above example, we have added the ImagePicker widget to the floating action button. When the user presses the button, the _getImage() function is called, which opens the gallery and allows the user to select an image. Once the user selects an image, the _image variable is updated with the selected image, and the UI is updated with the selected image.

More Examples

Working with media files like images and videos is part and parcel of our modern day culture. We record ourselves, take selfies, record family events etc. If you target to create an application that involves capturing images from the camera, picking existing images from the gallery, picking or capturing videos then this tutorial is for you.

We will be using the Flutter image_picker package. From this tutorial you will learn:

  1. How to Pick images from the Gallery.
  2. How to Capture images from the Camera.
  3. How to Pick Videos from the Gallery.
  4. How to Capture Videos from the Camera.

Step 1: Install image_picker

To install it go to your pubspec.yaml and declare image_picker as a flutter dependency as follows:

dependencies:
image_picker: ^0.8.4+2

Then sync.

You can also download it into your project from the commandline using the following command:

flutter pub add image_picker

Step 2: Setup iOS and Android

Now that you've installed the package, you need to step up your platform. It is different in iOS and Android.

iOS

To use this package in iOS you need iOS 9.0 or higher.Starting with version 0.8.1 of the package, the iOS implementation uses PHPicker to pick (multiple) images on iOS 14 or higher. As a result of implementing PHPicker it becomes impossible to pick HEIC images on the iOS simulator in iOS 14+. This is a known issue. Please test this on a real device, or test with non-HEIC images until Apple solves this issue.

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.

Android

For Android no configuration is required.

It is no longer required to add android:requestLegacyExternalStorage="true" as an attribute to the <application> tag in AndroidManifest.xml, as image_picker has been updated to make use of scoped storage.

Note: Images and videos picked using the camera are saved to your application's local cache, and should therefore be expected to only be around temporarily.

Step 3: Write Code

Start by importing it:

import 'package:image_picker/image_picker.dart';

Then instantiate the ImagePicker as follows:

    final ImagePicker _picker = ImagePicker();

Then pick an image from the gallery as follows as follows:

    // Pick an image
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);

And if you want to capture an image from Camera use the following code:

    // Capture a photo
final XFile? photo = await _picker.pickImage(source: ImageSource.camera);

If you want to pick a video from the gallery use the following code:

    // Pick a video
final XFile? image = await _picker.pickVideo(source: ImageSource.gallery);

If you want to capture a video from the camera use the following code:

    // Capture a video
final XFile? photo = await _picker.pickVideo(source: ImageSource.camera);

If you want to pick multuple images use the following code:

    // Pick multiple images
final List<XFile>? images = await _picker.pickMultiImage();
...

Full Example

  1. Install the Library as has been discussed above.
  2. Setup your platform as has been discussed above.
  3. Replace your main.dart with the following code:

main.dart


import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;

_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<XFile>? _imageFileList;
set _imageFile(XFile? value) {
_imageFileList = value == null ? null : [value];
}
dynamic _pickImageError;
bool isVideo = false;
VideoPlayerController? _controller;
VideoPlayerController? _toBeDisposed;
String? _retrieveDataError;
final ImagePicker _picker = ImagePicker();
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();
Future<void> _playVideo(XFile? file) async {
if (file != null && mounted) {
await _disposeVideoController();
late VideoPlayerController controller;
if (kIsWeb) {
controller = VideoPlayerController.network(file.path);
} else {
controller = VideoPlayerController.file(File(file.path));
}
_controller = controller;
// In web, most browsers won't honor a programmatic call to .play
// if the video has a sound track (and is not muted).
// Mute the video so it auto-plays in web!
// This is not needed if the call to .play is the result of user
// interaction (clicking on a "play" button, for example).
final double volume = kIsWeb ? 0.0 : 1.0;
await controller.setVolume(volume);
await controller.initialize();
await controller.setLooping(true);
await controller.play();
setState(() {});
}
}
void _onImageButtonPressed(ImageSource source,
{BuildContext? context, bool isMultiImage = false}) async {
if (_controller != null) {
await _controller!.setVolume(0.0);
}
if (isVideo) {
final XFile? file = await _picker.pickVideo(
source: source, maxDuration: const Duration(seconds: 10));
await _playVideo(file);
} else if (isMultiImage) {
await _displayPickImageDialog(context!,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final pickedFileList = await _picker.pickMultiImage(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
);
setState(() {
_imageFileList = pickedFileList;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
} else {
await _displayPickImageDialog(context!,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final pickedFile = await _picker.pickImage(
source: source,
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
);
setState(() {
_imageFile = pickedFile;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
}
}

void deactivate() {
if (_controller != null) {
_controller!.setVolume(0.0);
_controller!.pause();
}
super.deactivate();
}

void dispose() {
_disposeVideoController();
maxWidthController.dispose();
maxHeightController.dispose();
qualityController.dispose();
super.dispose();
}
Future<void> _disposeVideoController() async {
if (_toBeDisposed != null) {
await _toBeDisposed!.dispose();
}
_toBeDisposed = _controller;
_controller = null;
}
Widget _previewVideo() {
final Text? retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_controller == null) {
return const Text(
'You have not yet picked a video',
textAlign: TextAlign.center,
);
}
return Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatioVideo(_controller),
);
}
Widget _previewImages() {
final Text? retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFileList != null) {
return Semantics(
child: ListView.builder(
key: UniqueKey(),
itemBuilder: (context, index) {
// Why network for web?
// See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform
return Semantics(
label: 'image_picker_example_picked_image',
child: kIsWeb
? Image.network(_imageFileList![index].path)
: Image.file(File(_imageFileList![index].path)),
);
},
itemCount: _imageFileList!.length,
),
label: 'image_picker_example_picked_images');
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
Widget _handlePreview() {
if (isVideo) {
return _previewVideo();
} else {
return _previewImages();
}
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await _picker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
if (response.type == RetrieveType.video) {
isVideo = true;
await _playVideo(response.file);
} else {
isVideo = false;
setState(() {
_imageFile = response.file;
_imageFileList = response.files;
});
}
} else {
_retrieveDataError = response.exception!.code;
}
}

Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return _handlePreview();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: _handlePreview(),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Semantics(
label: 'image_picker_example_from_gallery',
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.gallery, context: context);
},
heroTag: 'image0',
tooltip: 'Pick Image from gallery',
child: const Icon(Icons.photo),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMultiImage: true,
);
},
heroTag: 'image1',
tooltip: 'Pick Multiple Image from gallery',
child: const Icon(Icons.photo_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.camera, context: context);
},
heroTag: 'image2',
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'video0',
tooltip: 'Pick Video from gallery',
child: const Icon(Icons.video_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'video1',
tooltip: 'Take a Video',
child: const Icon(Icons.videocam),
),
),
],
),
);
}
Text? _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError!);
_retrieveDataError = null;
return result;
}
return null;
}
Future<void> _displayPickImageDialog(
BuildContext context, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add optional parameters'),
content: Column(
children: <Widget>[
TextField(
controller: maxWidthController,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration:
InputDecoration(hintText: "Enter maxWidth if desired"),
),
TextField(
controller: maxHeightController,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration:
InputDecoration(hintText: "Enter maxHeight if desired"),
),
TextField(
controller: qualityController,
keyboardType: TextInputType.number,
decoration:
InputDecoration(hintText: "Enter quality if desired"),
),
],
),
actions: <Widget>[
TextButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('PICK'),
onPressed: () {
double? width = maxWidthController.text.isNotEmpty
? double.parse(maxWidthController.text)
: null;
double? height = maxHeightController.text.isNotEmpty
? double.parse(maxHeightController.text)
: null;
int? quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
onPick(width, height, quality);
Navigator.of(context).pop();
}),
],
);
});
}
}
typedef void OnPickImageCallback(
double? maxWidth, double? maxHeight, int? quality);
class AspectRatioVideo extends StatefulWidget {
AspectRatioVideo(this.controller);
final VideoPlayerController? controller;

AspectRatioVideoState createState() => AspectRatioVideoState();
}
class AspectRatioVideoState extends State<AspectRatioVideo> {
VideoPlayerController? get controller => widget.controller;
bool initialized = false;
void _onVideoControllerUpdate() {
if (!mounted) {
return;
}
if (initialized != controller!.value.isInitialized) {
initialized = controller!.value.isInitialized;
setState(() {});
}
}

void initState() {
super.initState();
controller!.addListener(_onVideoControllerUpdate);
}

void dispose() {
controller!.removeListener(_onVideoControllerUpdate);
super.dispose();
}

Widget build(BuildContext context) {
if (initialized) {
return Center(
child: AspectRatio(
aspectRatio: controller!.value.aspectRatio,
child: VideoPlayer(controller!),
),
);
} else {
return Container();
}
}
}

Reference

Find the reference links below:

NumberLink
1.Download Example
2.Read more

Conclusion

The ImagePicker widget is a powerful and useful widget in Flutter that allows the user to select an image from the device's gallery or take a new picture using the camera. In this article, we have discussed the steps to use the ImagePicker widget in Flutter. By following these steps, you can easily add the ImagePicker widget to your Flutter project and create a beautiful and efficient user interface.