In this blog post, I will show you how to use the camera package to take a picture in Flutter. Furthermore, I will provide an example of how to deal with the result file. In this example, I will open another page to display the picture. Please note that even though most of the features of the camera package are working, the plugin is still under development and some of the APIs might change.
Setup the project
Before we can start with coding, we are going to add the camera package to the project.
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
camera: ^0.9.4+14
Do not forget to install the dependency, running the following command:
flutter pub get
This is also a good time to make sure your settings for Android and IOs are correct. For Android, you have to make sure the minSdkVersion in the android/app/build.gradle file is at least 21. For IOs, you only have to make a change if you compile for a version below 10.0. The instructions with those changes are listed here.
Preview of the camera
Before I can show the preview of the camera, I need to initialize the cameras. I do this by calling the availableCameras method. This method is provided by the camera package. This method returns the available cameras on the device running the application. Since the method is asynchronous I delay the startup of the application till they are loaded.
List<CameraDescription> cameras = [];
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
runApp(
const MaterialApp(
debugShowCheckedModeBanner: false,
home: CameraApp(),
),
);
}
Now I have a list of cameras. Let’s use this to create a new CameraController. To create a new camera controller I need a camera and a resolution. In this example, I will use the maximum resolution and the first camera. To update the view with the preview of the camera, I have to wait till the controller is initialized, to call the setState method. After this method, the Widget will update and show the current preview of the camera.
To show the current view of the camera controller, I can use the CameraPreview Widget. This Widget shows the current result of the camera. I use the SizedBox to make the CameraPreview occupy the full screen.
class CameraApp extends StatefulWidget {
const CameraApp({Key? key}) : super(key: key);
@override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
late CameraController controller;
@override
void initState() {
super.initState();
controller = CameraController(cameras[0], ResolutionPreset.max);
controller.initialize().then((_) {
setState(() {});
});
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!controller.value.isInitialized) {
return Container();
}
return Scaffold(
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: CameraPreview(controller),
),
);
}
}
Taking a picture
Now that the application shows the current result of the view of the camera. Let’s take a picture. Before I take a picture, let’s first add a button to the Widget.
return Scaffold(
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: CameraPreview(controller),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.camera),
onPressed: () {
// todo
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
On the pressing of the button, I can take a picture. I can take a picture by calling the corresponding method on the controller. This method returns a file. This file can be used for different methods, but I provide the file to the display widget to show the result of the camera.
controller.takePicture().then((value) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ImageDisplayWidget(
imagePath: value.path,
),
),
);
});
The ImageDisplayWidget simply shows the image by displaying the file in the Image Widget.
class ImageDisplayWidget extends StatelessWidget {
final String imagePath;
const ImageDisplayWidget({Key? key, required this.imagePath}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Image.file(File(imagePath))),
);
}
}
This is all that is necessary to take a picture in a Flutter application! The code of this example can be found here on Github. If you still have any questions, comments, suggestions or other remarks feel free to let me know!