Many apps require working with the device’s cameras to take photos and videos.Flutter provides the camera pluginfor this purpose. The camera plugin provides tools to get a list of theavailable cameras, display a preview coming from a specific camera, and takephotos or videos.

This recipe demonstrates how to use the camera plugin to display a preview, take a photo, and display it.

Directions

  • Add the required dependencies
  • Get a list of the available cameras
  • Create and initialize the CameraController
  • Use a CameraPreview to display the camera’s feed
  • Take a picture with the CameraController
  • Display the picture with an Image Widget

1. Add the required dependencies

To complete this recipe, you need to add three dependencies to your app:

  • camera - Provides tools to work with the cameras on device
  • path_provider - Finds the correct paths to store images
  • path - Creates paths that work on any platform
  1. dependencies:
  2. flutter:
  3. sdk: flutter
  4. camera:
  5. path_provider:
  6. path:

2. Get a list of the available cameras

Next, you can get a list of available cameras using the camera plugin.

  1. // Obtain a list of the available cameras on the device.
  2. final cameras = await availableCameras();
  3. // Get a specific camera from the list of available cameras
  4. final firstCamera = cameras.first;

3. Create and initialize the CameraController

Once you have a camera to work with, you need to create and initialize aCameraController. This process establishes a connection to the device’s camerathat allows you to control the camera and display a preview of the camera’sfeed.

To achieve this, please:

  • Create a StatefulWidget with a companion State class
  • Add a variable to the State class to store the CameraController
  • Add a variable to the State class to store the Future returned from CameraController.initialize
  • Create and initialize the controller in the initState method
  • Dispose of the controller in the dispose method
  1. // A screen that takes in a list of Cameras and the Directory to store images.
  2. class TakePictureScreen extends StatefulWidget {
  3. final CameraDescription camera;
  4. const TakePictureScreen({
  5. Key key,
  6. @required this.camera,
  7. }) : super(key: key);
  8. @override
  9. TakePictureScreenState createState() => TakePictureScreenState();
  10. }
  11. class TakePictureScreenState extends State<TakePictureScreen> {
  12. // Add two variables to the state class to store the CameraController and
  13. // the Future
  14. CameraController _controller;
  15. Future<void> _initializeControllerFuture;
  16. @override
  17. void initState() {
  18. super.initState();
  19. // In order to display the current output from the Camera, you need to
  20. // create a CameraController.
  21. _controller = CameraController(
  22. // Get a specific camera from the list of available cameras
  23. widget.camera,
  24. // Define the resolution to use
  25. ResolutionPreset.medium,
  26. );
  27. // Next, you need to initialize the controller. This returns a Future
  28. _initializeControllerFuture = _controller.initialize();
  29. }
  30. @override
  31. void dispose() {
  32. // Make sure to dispose of the controller when the Widget is disposed
  33. _controller.dispose();
  34. super.dispose();
  35. }
  36. @override
  37. Widget build(BuildContext context) {
  38. // Fill this out in the next steps
  39. }
  40. }

Warning:If you do not initialize the CameraController, you cannot use the camerato display a preview and take pictures.

4. Use a CameraPreview to display the camera’s feed

Next, you can use the CameraPreview Widget from the camera package todisplay a preview of the camera’s feed.

Remember: You must wait until the controller has finished initializing beforeworking with the camera. Therefore, you must wait for the_initializeControllerFuture created in the previous step to complete beforeshowing a CameraPreview.

You can use aFutureBuilderfor exactly this purpose.

  1. // You must wait until the controller is initialized before displaying the
  2. // camera preview. Use a FutureBuilder to display a loading spinner until the
  3. // controller has finished initializing
  4. FutureBuilder<void>(
  5. future: _initializeControllerFuture,
  6. builder: (context, snapshot) {
  7. if (snapshot.connectionState == ConnectionState.done) {
  8. // If the Future is complete, display the preview
  9. return CameraPreview(_controller);
  10. } else {
  11. // Otherwise, display a loading indicator
  12. return Center(child: CircularProgressIndicator());
  13. }
  14. },
  15. )

5. Take a picture with the CameraController

You can also use the CameraController to take pictures using thetakePicturemethod. In this example, create a FloatingActionButton that takes a pictureusing the CameraController when a user taps on the button.

Saving a picture requires 3 steps:

  • Ensure the camera is initialized
  • Construct a path that defines where the picture should be saved
  • Use the controller to take a picture and save the result to the pathIt is good practice to wrap these operations in a try / catch block in orderto handle any errors that might occur.
  1. FloatingActionButton(
  2. child: Icon(Icons.camera_alt),
  3. // Provide an onPressed callback
  4. onPressed: () async {
  5. // Take the Picture in a try / catch block. If anything goes wrong,
  6. // catch the error.
  7. try {
  8. // Ensure the camera is initialized
  9. await _initializeControllerFuture;
  10. // Construct the path where the image should be saved using the path
  11. // package.
  12. final path = join(
  13. // In this example, store the picture in the temp directory. Find
  14. // the temp directory using the `path_provider` plugin.
  15. (await getTemporaryDirectory()).path,
  16. '${DateTime.now()}.png',
  17. );
  18. // Attempt to take a picture and log where it's been saved
  19. await _controller.takePicture(path);
  20. } catch (e) {
  21. // If an error occurs, log the error to the console.
  22. print(e);
  23. }
  24. },
  25. )

6. Display the picture with an Image Widget

If you take the picture successfully, you can then display the saved pictureusing an Image widget. In this case, the picture is stored as a file onthe device.

Therefore, you must provide a File to the Image.file constructor. Youcan create an instance of the File class by passing in the path you created inthe previous step.

  1. Image.file(File('path/to/my/picture.png'))

Complete Example

  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:camera/camera.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:path/path.dart' show join;
  6. import 'package:path_provider/path_provider.dart';
  7. Future<void> main() async {
  8. // Obtain a list of the available cameras on the device.
  9. final cameras = await availableCameras();
  10. // Get a specific camera from the list of available cameras
  11. final firstCamera = cameras.first;
  12. runApp(
  13. MaterialApp(
  14. theme: ThemeData.dark(),
  15. home: TakePictureScreen(
  16. // Pass the appropriate camera to the TakePictureScreen Widget
  17. camera: firstCamera,
  18. ),
  19. ),
  20. );
  21. }
  22. // A screen that allows users to take a picture using a given camera
  23. class TakePictureScreen extends StatefulWidget {
  24. final CameraDescription camera;
  25. const TakePictureScreen({
  26. Key key,
  27. @required this.camera,
  28. }) : super(key: key);
  29. @override
  30. TakePictureScreenState createState() => TakePictureScreenState();
  31. }
  32. class TakePictureScreenState extends State<TakePictureScreen> {
  33. CameraController _controller;
  34. Future<void> _initializeControllerFuture;
  35. @override
  36. void initState() {
  37. super.initState();
  38. // In order to display the current output from the Camera, you need to
  39. // create a CameraController.
  40. _controller = CameraController(
  41. // Get a specific camera from the list of available cameras
  42. widget.camera,
  43. // Define the resolution to use
  44. ResolutionPreset.medium,
  45. );
  46. // Next, you need to initialize the controller. This returns a Future
  47. _initializeControllerFuture = _controller.initialize();
  48. }
  49. @override
  50. void dispose() {
  51. // Make sure to dispose of the controller when the Widget is disposed
  52. _controller.dispose();
  53. super.dispose();
  54. }
  55. @override
  56. Widget build(BuildContext context) {
  57. return Scaffold(
  58. appBar: AppBar(title: Text('Take a picture')),
  59. // You must wait until the controller is initialized before displaying the
  60. // camera preview. Use a FutureBuilder to display a loading spinner until
  61. // the controller has finished initializing
  62. body: FutureBuilder<void>(
  63. future: _initializeControllerFuture,
  64. builder: (context, snapshot) {
  65. if (snapshot.connectionState == ConnectionState.done) {
  66. // If the Future is complete, display the preview
  67. return CameraPreview(_controller);
  68. } else {
  69. // Otherwise, display a loading indicator
  70. return Center(child: CircularProgressIndicator());
  71. }
  72. },
  73. ),
  74. floatingActionButton: FloatingActionButton(
  75. child: Icon(Icons.camera_alt),
  76. // Provide an onPressed callback
  77. onPressed: () async {
  78. // Take the Picture in a try / catch block. If anything goes wrong,
  79. // catch the error.
  80. try {
  81. // Ensure the camera is initialized
  82. await _initializeControllerFuture;
  83. // Construct the path where the image should be saved using the path
  84. // package.
  85. final path = join(
  86. // In this example, store the picture in the temp directory. Find
  87. // the temp directory using the `path_provider` plugin.
  88. (await getTemporaryDirectory()).path,
  89. '${DateTime.now()}.png',
  90. );
  91. // Attempt to take a picture and log where it's been saved
  92. await _controller.takePicture(path);
  93. // If the picture was taken, display it on a new screen
  94. Navigator.push(
  95. context,
  96. MaterialPageRoute(
  97. builder: (context) => DisplayPictureScreen(imagePath: path),
  98. ),
  99. );
  100. } catch (e) {
  101. // If an error occurs, log the error to the console.
  102. print(e);
  103. }
  104. },
  105. ),
  106. );
  107. }
  108. }
  109. // A Widget that displays the picture taken by the user
  110. class DisplayPictureScreen extends StatelessWidget {
  111. final String imagePath;
  112. const DisplayPictureScreen({Key key, this.imagePath}) : super(key: key);
  113. @override
  114. Widget build(BuildContext context) {
  115. return Scaffold(
  116. appBar: AppBar(title: Text('Display the Picture')),
  117. // The image is stored as a file on the device. Use the `Image.file`
  118. // constructor with the given path to display the image
  119. body: Image.file(File(imagePath)),
  120. );
  121. }
  122. }