How to add Camera support to a Flutter app
I’d say 90% of the apps I’ve developed required a camera feature. It can be anything from capturing pictures, loading image paths from a gallery, to manipulating images. In this tutorial, I’m going to show you how to easily add a camera feature to a Flutter app.
What Are We Building?
We’re going to be extending upon our existing Beers App. Our aim is to be able to add new beers to our application. It will be important to capture an image of the beer we’re adding. We’ll also add some text inputs to collect the name, country of origin, and the beer’s ABV. To help put this all together, we’re going to create a new AddBeerScreen
widget.
Basic functionality
When I had to figure this out, the first thing I did was search for a camera package in Flutter. I came across the following:
As per the documentation, we have to set the minSdkVersion
to 21 or higher in android/app/build.gradle
for an Android app. For iOS, we need to edit ios/Runner/Info.plist
and add the following key / values for camera permissions. For a mobile application to have access to the camera, the user has to grant it permissions.
<key>NSCameraUsageDescription</key>
<string>Can I use the camera please?</string>
<key>NSMicrophoneUsageDescription</key>
<string>Can I use the mic please?</string>
Before we get started creating a camera widget, we need to add camera dependencies to pubspec.yaml
. Please follow the instructions for the camera package to install it.
dependencies:
flutter:
sdk: flutter
http: 0.12.0+1
camera: ^0.4.2
First, I created a camera
folder in the screens
directory and added a camera.dart
. The code in the documentation doesn’t fit my structure perfectly, so you’ll want to modify the implementation slightly:
We’ll also update the bottom navigation, instantiating a new instance of the CameraWidget
:
Here is the result:
Add Beer Screen
Okay, we have a basic version working, but what we want to achieve during this tutorial is much more. Here is the view that we’re going for:
- The whole view needs to be in a scrolling widget. We need this for a simple reason — our view has inputs so if we want to scroll down to reach them we need a
SingleChildScrollView
. This widget lets us build a view, which automatically has a scrolling function.SingleChildScrollView
creates a box in which a single widget can be scrolled. - Camera view with a preview of the captured picture.
- Buttons for switching between front and back camera.
- Inputs for beer name, country name and ABV* and a blue button for submit.
*Alcohol by volume (abbreviated as ABV, abv, or alc/vol) is a standard measure of how much alcohol (ethanol) is contained in a given volume of an alcoholic beverage (expressed as a volume percent).
The first thing we need to declare are some values:
scaffoldKey
— key which we need to display errors usingscaffoldKey.currentState.showSnackBar
.cameras
— we will keep a reference for available camerascontroller
— to show the camera preview on the screenisReady, showCamera, imagePath
— variables for keeping state and the image pathnameController, countryController, abvController
— input controllers
Next, we need to initialise the view’s state. It is very important for us to first check for an available camera. Camera.dart
offers an asynchronous method for that. The setupCameras
method also initialises CameraController
and manages the isReady
state.
When our cameras are initialised, it’s time to add a scrollable layout. I use SingleChildScrollView.
I then add a Column
widget with the camera preview and image preview. There is also a section for the camera capture button. After that, we have a camera options widget and input’s widget.
Let’s start with the cameraPreviewWidget
. This method returns an AspectRatio
widget, which is responsible for returning the child with a specific aspect ratio. Our child here is a CameraPreview
widget.
If we have a camera, we also need a section to show the picture that was taken. The imagePreviewWidget
is responsible for this. Basically, it is just a container with SizedBox for displaying an Image from the imagePath. The image that was taken is always saved to the phone’s memory, so for displaying the image, I use Image.file
.
The next widget is simply a Row
with an icon. The Icon has an onPressed
method. If the camera controller isInitialized
, the user can call onTakePictureButtonPressed
.
The onTakePictureButtonPressed
method is asynchronous and is responsible for creating a directory with a specific path. This file path is used for image captures. The image will be saved to the filePath
.
Not every picture is perfect, so to give the user an opportunity to edit the picture, I’ve also added a editCaptureControlRowWidaget
. After the button is pressed, the camera will become visible again and the user can retake the picture.
The next section contains two buttons which represent the camera options. A user can choose between the front or back camera. The cameraOptionsWidget
returns a Row widget with SizedBoxes
containing Radio Icons.
The radio button has an onChanged
function, where I call the onNewCameraSelected
method. This method reinitialised the controller with the current cameraDescription.
And finally, it’s time for the last section. To create a beer in app, we need some inputs where user can type in the information. We use for it a simple column with children that render Padding
widgets with TextField
widgets.
Summary
And here’s the final result! We’re able to switch between the front and rear cameras, take a picture and add some extra information in the input fields:
After reading this tutorial, I hope this makes it a bit easier implementing a camera feature in your applications. Thankfully, implementing a camera feature in a Flutter app isn’t so difficult, but there are a few differences in building the camera layout compared to other technologies, such as ReactNative. If you like my tutorial, visit our blog and there you’ll find Flutter, React Native, GraphQL and other articles.
Stay tuned because the next Flutter article is coming… 🐺
PS. You can also download the full source code.