How To Get Image From Camera & Gallery In Flutter

After trying several packages(camera, flutter_camera, camera_camera), I finally landed one that works easily for photos: image_picker

It worked like a charm!!! Below is what it looks like in the end. I needed it inside a TabBarView(), but you can put it anywhere.

body: TabBarView(
  children: [
    CameraView(), <= Implementation of this widget
    const Icon(Icons.favorite_border_outlined),
    const Icon(Icons.public),
    const Icon(Icons.settings),
  ],
)

I followed this tutorial. Below is my note on this implementation.

Major Components:

  1. a StatefulWidget CameraView as the final layout return.

  2. Inside the state of this CameraView class, I need (1) a function to get the image file given a path, (2) a function to source the image, and (3) a class variable _image to track if the image is loaded.

  3. The above two functions should be inside CameraView because they update the instance variable _image. There is also a helper function to create custom buttons outside the CameraView class.

So … four components to understand: 2 functions, a variable to track the availability of the image, and a helper function.

Implementation Of Each Component

A function to get the image file from a path

  Future<File> saveFilePermanently(String imagePath) async {
    final directory = await getApplicationDocumentsDirectory();
    final name = basename(imagePath);
    final image = File('${directory.path}/$name');
    return File(imagePath).copy(image.path);
  }

A function to source the image and update the state _image

  Future getImage(ImageSource source) async {
    try {
      final image = await ImagePicker().pickImage(
        source: source,
      );
      if (image == null) return;
      final imagePermanent = await saveFilePermanently(image.path);
      setState(() {
        _image = imagePermanent;
      });
    } on PlatformAssetBundle catch (e) {
      devtools.log('Failed to get image: $e');
    }
  }

A variable to track the availability of the image and a tertiary operator to display it only when available.

File? _image; # class level
_image != null # inside the final layout return
    ? Image.file(
        _image!,
        width: 250,
        height: 250,
        fit: BoxFit.cover,
      )
    : Image.network(
        'https://media-exp1.licdn.com/dms/image/C4D03AQHlTQC59YWK9g/profile-displayphoto-shrink_400_400/0/1641955686415?e=1675900800&v=beta&t=QZpjjws2t69rvxl4XY16zyrkauWwLbl9YWQdX_mFN1Y',
      ),

A helper function for custom buttons

Widget imageButton({
  required String title,
  required IconData icon,
  required VoidCallback onClick,
}) {
  return SizedBox(
    width: 280,
    child: ElevatedButton(
      child: Row(
        children: [
          Icon(icon),
          const SizedBox(
            width: 20,
          ),
          Text(title),
        ],
      ),
      onPressed: onClick,
    ),
  );
}

Put them all together, the code is here. The final returned widget is used here.

Now I can sleep well. Excepted, I feel too excited….