How to Use Camera in Flutter — Camera Package
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.
Table of Contents
· 1. Setting up The Project
· 2. Get a List of Available Cameras
· 3. Create and Initialize The Camera
· 4. Use a Camera Preview to Display the Camera’s Feed
· 5. Take a Picture With the Camera Controller
· 6. Create a Button to Flip The Camera
· 7. Display the Picture With an Image Widget
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:
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. ✌️