ImagePicker Widget – Flutter Guide By Flutter Agency

· 10 min read
Flutter Guide By Flutter Agency - ImagePicker widget
Flutter Guide By Flutter Agency - ImagePicker widget

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.6.7 “. 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.6.7 ” plugin into pubspec.yaml under dependencies.

Step 1: Adding dependencies to project

dependencies:
   image_picker 0.6.7

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 FAB-Button

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.

Dialog Button

When users click on Pick Button we will call _onImageButtonPressed()

  void _onImageButtonPressed(ImageSource source, {BuildContext context}) async {
    if (_controller != null) {
      await _controller.setVolume(0.0);
    }
    await _displayPickImageDialog(context,
        (double maxWidth, double maxHeight, int quality) async {
      try {
        final pickedFile = await _picker.getImage(
          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.

Picked-Image

Uploaded Image

Complete source code for this is as below :

import 'dart:io';
import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_player/video_player.dart';

class ImagePickerScreen extends StatefulWidget {
  ImagePickerScreen({
    Key key,
    this.title,
  }) : super(key: key);

  final String title;

  @override
  _ImagePickerScreenState createState() => _ImagePickerScreenState();
}

class _ImagePickerScreenState extends State<ImagePickerScreen> {
  PickedFile _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<void> _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, {BuildContext context}) async {
    if (_controller != null) {
      await _controller.setVolume(0.0);
    }
    await _displayPickImageDialog(context,
        (double maxWidth, double maxHeight, int quality) async {
      try {
        final pickedFile = await _picker.getImage(
          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<void> _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<void> retrieveLostData() async {
    final LostData response = await _picker.getLostData();
    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) {
    return Scaffold(
      body: Center(
        child: 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 _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: <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),
            ),
          ),
        ],
      ),
    );
  }

  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>[
              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();
                  }),
            ],
          );
        });
  }
}

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 GuideFlutter ProjectsCode 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.

Leave a Reply