How to Use Camera in Flutter — Camera Package

Fernando Putra
6 min readApr 13, 2022

--

Nowadays, almost every mobile app out there requires working with the device’s cameras to perform various tasks. To access the device’s camera on Android or iOS, we need to know Kotlin or Swift programming languages, understand the APIs, and write separate code.

Thankfully, Flutter already provides a package for iOS, Android, and the Web that allows access to the device’s camera, named camera package. This package provides tools to get a list of the available cameras, display a preview from a specific camera, and take photos or videos.

In this reading, we’ll learn how to access the device’s camera (on Android or iOS) with the camera package to take a picture and display it.

1. Setting up The Project

First, we must add the required dependency, the camera package, to your pubspec.yaml file.

dependencies:
camera: ^0.9.4+19

Or run the following command:

$ flutter pub add camera
// This will add the same line to your package's pubspec.yaml

Next, we need to add permission configuration for Android and iOS.

  • For Android, we have to change the minimum Android SDK version to 21 (or higher) in your android/app/build.gradle
android {
// ...
defaultConfig {
minSdkVersion 21
}
}
  • For iOS 10 or higher, we have to add camera and microphone permission by adding lines below inside ios/Runner/Info.plist
<key>NSCameraUsageDescription</key>
<string>This app needs access to camera when used</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to microphone when used</string>

Lastly, replace the content of your main.dart file with the following code, and we’re all set.

2. Get a List of Available Cameras

To get a list of available cameras, you have to call the availableCameras() method provided by the camera package.

// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();

Make sure to call the method inside the async function, as it has to wait to retrieve the device’s available cameras. You can follow the following code:

await availableCameras().then(
(value) => Navigator.push(
context, MaterialPageRoute(
builder: (_) => CameraPage(cameras: value))
),
);

This will obtain a list of the available cameras and pass it to the CameraPage. This is how the home_page.dart looks.

3. Create and Initialize The Camera

Once we get a camera list from the home_page.dart file, we have to create and initialize a CameraController. This class is responsible for establishing a connection to the device’s camera that allows you to control the camera and display a preview of the camera’s feed.

First, declare the CameraController with a late modifier inside the camera_page.dart file because we’ll initialize it later. This page should be a StatefulWidget because we will override the initState and add a feature to flip the camera.

class CameraPage extends StatefulWidget {
final List<CameraDescription>? cameras;
const CameraPage(
{Key? key, required this.cameras}) : super(key:key);
@override
State<CameraPage> createState() => _CameraPageState();
}
class _CameraPageState extends State<CameraPage> {
late CameraController _cameraController;
// ...

Next, create a method to initialize a selected camera.

Future initCamera(CameraDescription cameraDescription) async {
// create a CameraController
_cameraController = CameraController(
cameraDescription, ResolutionPreset.high);
// Next, initialize the controller. This returns a Future.
try {
await _cameraController.initialize().then((_) {
if (!mounted) return;
setState(() {});
});
} on CameraException catch (e) {
debugPrint("camera error $e");
}
}

In this method, we create a CameraController that will load the camera description with the resolution of our choice and initialize the controller to start the camera.

After that, we call initCamera inside the initState() method and pass the camera description. Usually, the size of the camera list will be 2, and the 0 index is for the rear camera, and the 1 index for the front camera.

@override
void initState() {
super.initState();
// initialize the rear camera
initCamera(widget.cameras![0]);
}

Make sure to dispose of the CameraController in the dispose() method.

@override
void dispose() {
// Dispose of the controller when the widget is disposed.
_cameraController.dispose();
super.dispose();
}

4. Use a Camera Preview to Display the Camera’s Feed

Now that we’ve finished initializing the camera, we can start using the CameraPreview widget from the camera package to display a preview of the camera’s feed.

You can follow the following code to display the camera preview. CircularProgressIndicator will be displayed until the CameraController has finished initializing.

class _CameraPageState extends State<CameraPage> {
// ...
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: _cameraController.value.isInitialized
? CameraPreview(_cameraController)
: const Center(child:
CircularProgressIndicator())));
}
}

The preview will look like this:

5. Take a Picture With the Camera Controller

To take a picture, we can use the CameraController and make a call to the takePicture() method, which returns an XFile, a cross-platform, simplified File abstraction.

First, create a method that calls takePicture() method from the CameraController, stored the returned XFile, and pass the XFile to preview_page.dart.

Future takePicture() async {
if (!_cameraController.value.isInitialized) {return null;}
if (_cameraController.value.isTakingPicture) {return null;}
try {
await _cameraController.setFlashMode(FlashMode.off);
XFile picture = await _cameraController.takePicture();
Navigator.push(context, MaterialPageRoute(
builder: (context) => PreviewPage(
picture: picture,
)));
} on CameraException catch (e) {
debugPrint('Error occured while taking picture: $e');
return null;
}
}

Then, create an IconButton to take a picture and call the method we made into the onPressed parameter.

IconButton(
onPressed: takePicture,
iconSize: 50,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
child: const Icon(Icons.circle, color: Colors.white),
)

6. Create a Button to Flip The Camera

To toggle between the front and rear cameras, we have to reinitialize the camera by providing the new camera’s index to the initCamera() method.

First, define a Boolean variable to flag whether the rear camera is selected.

bool _isRearCameraSelected = true;

Then, create an IconButton to toggle between the rear and front cameras.

IconButton(
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
iconSize: 30,
icon: Icon(
_isRearCameraSelected
? CupertinoIcons.switch_camera
: CupertinoIcons.switch_camera_solid,
color: Colors.white),
onPressed: () {
setState(() => _isRearCameraSelected = !_isRearCameraSelected);
initCamera(widget.cameras![_isRearCameraSelected ? 0 : 1]);
},
)

In the code above, if the _isRearCameraSelected Boolean is true, passed 0 as the index to the cameras (to flip to the front camera). Otherwise, passed 1 as the index (to flip to the rear camera).

After all, this is how the camera_page.dart looks.

7. Display the Picture With an Image Widget

Once we got an XFile from the camera_page.dart, we can display the captured image with the help of Image widget. Since the picture is stored as a file on the device, we must provide a File to the Image.file constructor. We can create an instance of the File class by passing the path of the XFile.

Image.file(File(picture.path));

This is how the preview_page.dart looks.

The final result will look like this:

Congrats, you have learned how to use the camera in your flutter project. I hope this article helped you to get started with the camera package😁.

You can access the repository of this reading here on GitHub.

Thank you for reading! If you found this article helpful, kindly share it with your friends and follow my profile for future updates. Your support is much appreciated! PS: It would mean even more if you donate a pizza 🍕 here. ✌️

--

--