ImagePicker Widget – Flutter Guide By Flutter Agency
In this article, we are going to learn ImagePicker Widget to pick images from the gallery in a flutter.
What is ImagePicker Widget?
A Flutter plugin library for both iOS and Android that is been used to pick an image from a mobile phone gallery or even you can take a new photo with the camera.
Let’s straight away start to implement the flutter ImagePicker Widget in our flutter app.
Get the latest version of the ImagePicker Widget from the official website. When I am writing this article we are using the plugin with version ” image_picker 0.8.5+3“. Let’s follow instructions as per the official document. If there are any changes that occur in the future we need to implement the plugin with new and latest instructions.
Now, put this ” image_picker 0.8.5+3 ” plugin into pubspec.yaml under dependencies.
Step 1: Adding dependencies to project
image_picker: ^1.1.2 video_player: ^2.9.1
Step 2: Import image_picker.dart
Now, as we have added the required library in our project now users need to import the picker library wherever required.
import 'package:image_picker/image_picker.dart';
Ways to implement ImagePicker Widget will defer depending on the type of platform the user is implementing.
For Android:
For Android with API 29+ no more configuration required – the plugin should work like a charm.
If a user has API < 29 then follow instructions like below :
Add android:requestLegacyExternalStorage=”true” as an attribute to the tag in AndroidManifest.xml.The attribute is false by default on apps targeting Android Q.
Create a FloatingActionButton Widget which is used to choose an image from the gallery or choose a camera.
The code snippet will look like below :
floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ FloatingActionButton( onPressed: () { isVideo = false; _onImageButtonPressed( ImageSource.gallery, context: context, ); }, heroTag: 'image0', tooltip: 'Pick 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: 'image1', tooltip: 'Take a Photo', child: const Icon(Icons.camera_alt), ), ), ], ),
We will get a FAB(FloatingActionButton) button like below :
Image Picker
In this example when users click on FAB Button user will get a dialog where users can enter the information like maxWidth, maxHeight, Quality parameters. into TextField Widget The code snippet will look like below :
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>[ FlatButton( child: const Text('CANCEL'), onPressed: () { Navigator.of(context).pop(); }, ), FlatButton( 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(); }), ], ); }); } }
We will get output like below.
When users click on Pick Button we will call _onImageButtonPressed().
void _onImageButtonPressed(ImageSource source, {required BuildContext context}) async { if (_controller != null) { await _controller?.setVolume(0.0); } await _displayPickImageDialog(context, (double maxWidth, double maxHeight, int quality) async { try { final XFile? pickedFile = await _picker.pickImage( source: source, maxWidth: maxWidth, maxHeight: maxHeight, imageQuality: quality, ); setState(() { _imageFile = pickedFile; }); } catch (e) { setState(() { _pickImageError = e; }); } }); }
Once the user clicks on the pick button after inserting desire height/width and quality can select an image from the gallery or camera image will be shown to the user like the below screenshot.
Uploaded Image
Complete source code for this is as below :
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; import 'package:video_player/video_player.dart'; // Define your main function void main() { runApp(MyApp()); } // Main application widget class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'MateApp Flutter Demo', localizationsDelegates: const [ // Add localizations delegates here GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en', ''), // English Locale('es', ''), // Spanish ], theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: ImagePickerScreen(), ); } } class ImagePickerScreen extends StatefulWidget { ImagePickerScreen({ Key? key, this.title, }) : super(key: key); final String? title; @override _ImagePickerScreenState createState() => _ImagePickerScreenState(); } class _ImagePickerScreenState extends State { XFile? _imageFile; dynamic _pickImageError; bool isVideo = false; VideoPlayerController? _controller; String? _retrieveDataError; final ImagePicker _picker = ImagePicker(); final TextEditingController maxWidthController = TextEditingController(); final TextEditingController maxHeightController = TextEditingController(); final TextEditingController qualityController = TextEditingController(); Future _playVideo(PickedFile file) async { if (file != null && mounted) { await _disposeVideoController(); _controller = VideoPlayerController.file(File(file.path)); await _controller?.setVolume(1.0); await _controller?.initialize(); await _controller?.setLooping(true); await _controller?.play(); setState(() {}); } } void _onImageButtonPressed(ImageSource source, {required BuildContext context}) async { if (_controller != null) { await _controller?.setVolume(0.0); } await _displayPickImageDialog(context, (double maxWidth, double maxHeight, int quality) async { try { final XFile? pickedFile = await _picker.pickImage( source: source, maxWidth: maxWidth, maxHeight: maxHeight, imageQuality: quality, ); setState(() { _imageFile = pickedFile; }); } catch (e) { setState(() { _pickImageError = e; }); } }); } @override void deactivate() { if (_controller != null) { _controller?.setVolume(0.0); _controller?.pause(); } super.deactivate(); } @override void dispose() { _disposeVideoController(); maxWidthController.dispose(); maxHeightController.dispose(); qualityController.dispose(); super.dispose(); } Future _disposeVideoController() async { if (_controller != null) { await _controller?.dispose(); _controller = null; } } Widget _previewImage() { final Text? retrieveError = _getRetrieveErrorWidget(); if (retrieveError != null) { return retrieveError; } if (_imageFile != null) { return Image.file(File(_imageFile!.path)); } 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, ); } } Future 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 ; }); } } else { _retrieveDataError = response.exception?.code; } } @override Widget build(BuildContext context) { var defaultTargetPlatform; return Scaffold( body: Center( child: defaultTargetPlatform == TargetPlatform.android ? FutureBuilder( future: retrieveLostData(), builder: (BuildContext context, AsyncSnapshot 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 _previewImage(); 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, ); } } }, ) : (_previewImage()), ), floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ FloatingActionButton( onPressed: () { isVideo = false; _onImageButtonPressed( ImageSource.gallery, context: context, ); }, heroTag: 'image0', tooltip: 'Pick 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: 'image1', tooltip: 'Take a Photo', child: const Icon(Icons.camera_alt), ), ), ], ), ); } Text? _getRetrieveErrorWidget() { if (_retrieveDataError != null) { final Text result = Text(_retrieveDataError!); _retrieveDataError = null; return result; } return null; } Future _displayPickImageDialog( BuildContext context, OnPickImageCallback onPick) async { return showDialog( context: context, builder: (context) { return AlertDialog( title: Text('Add optional parameters'), content: Column( children: [ 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: const InputDecoration( hintText: "Enter quality if desired"), ), ], ), actions: [ 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 ?? 100, height ?? 100, quality ?? 100); Navigator.of(context).pop(); }), ], ); }); } } typedef void OnPickImageCallback( double maxWidth, double maxHeight, int quality);
Do not forget to comment if you need any assistance regarding this.
Keep Fluttering !!!
FlutterAgency.com is our portal Platform dedicated to Flutter Technology and Flutter Developers. The portal is full of cool resources from Flutter like Flutter Widget Guide, Flutter Projects, Code libs and etc.
FlutterAgency.com is one of the most popular online portal dedicated to Flutter Technology and daily thousands of unique visitors come to this portal to enhance their knowledge on Flutter.
Contemporary ventures
Recent blog
ready to get started?
Fill out the form below and we will be in touch soon!
"*" indicates required fields