0
0
Fluttermobile~20 mins

Camera access in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Camera Screen
This screen lets the user open the camera, take a photo, and display the photo on the screen.
Target UI
┌─────────────────────────────┐
│        Camera Screen        │
├─────────────────────────────┤
│                             │
│       [Camera Preview]      │
│                             │
│                             │
│                             │
│                             │
│                             │
│                             │
├─────────────────────────────┤
│  [Take Photo Button]         │
├─────────────────────────────┤
│  [Captured Photo Display]    │
│                             │
│                             │
│                             │
└─────────────────────────────┘
Show live camera preview filling most of the screen
Add a button labeled 'Take Photo' below the preview
When the button is pressed, capture a photo from the camera
Display the captured photo below the button
Handle camera permissions properly
Use Flutter's camera package for implementation
Starter Code
Flutter
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';

class CameraScreen extends StatefulWidget {
  @override
  State<CameraScreen> createState() => _CameraScreenState();
}

class _CameraScreenState extends State<CameraScreen> {
  CameraController? _controller;
  XFile? _imageFile;

  @override
  void initState() {
    super.initState();
    // TODO: Initialize camera controller here
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Camera Screen')),
      body: Column(
        children: [
          // TODO: Add camera preview widget here
          ElevatedButton(
            onPressed: () {
              // TODO: Add take photo logic here
            },
            child: Text('Take Photo'),
          ),
          // TODO: Show captured photo here
        ],
      ),
    );
  }
}
Task 1
Task 2
Task 3
Task 4
Solution
Flutter
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'dart:io';

class CameraScreen extends StatefulWidget {
  @override
  State<CameraScreen> createState() => _CameraScreenState();
}

class _CameraScreenState extends State<CameraScreen> {
  CameraController? _controller;
  XFile? _imageFile;
  late Future<void> _initializeControllerFuture;

  @override
  void initState() {
    super.initState();
    _setupCamera();
  }

  Future<void> _setupCamera() async {
    final cameras = await availableCameras();
    final firstCamera = cameras.first;
    _controller = CameraController(firstCamera, ResolutionPreset.medium);
    _initializeControllerFuture = _controller!.initialize();
    if (mounted) {
      setState(() {});
    }
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  Future<void> _takePhoto() async {
    try {
      await _initializeControllerFuture;
      final image = await _controller!.takePicture();
      setState(() {
        _imageFile = image;
      });
    } catch (e) {
      print('Error taking photo: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Camera Screen')),
      body: Column(
        children: [
          Expanded(
            flex: 3,
            child: _controller == null
                ? Center(child: CircularProgressIndicator())
                : FutureBuilder<void>(
                    future: _initializeControllerFuture,
                    builder: (context, snapshot) {
                      if (snapshot.connectionState == ConnectionState.done) {
                        return CameraPreview(_controller!);
                      } else {
                        return Center(child: CircularProgressIndicator());
                      }
                    },
                  ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: ElevatedButton(
              onPressed: _controller == null ? null : _takePhoto,
              child: Text('Take Photo'),
            ),
          ),
          Expanded(
            flex: 2,
            child: _imageFile == null
                ? Center(child: Text('No photo taken yet'))
                : Image.file(File(_imageFile!.path)),
          ),
        ],
      ),
    );
  }
}

We start by getting the list of available cameras asynchronously and pick the first one. Then we create a CameraController with medium resolution and initialize it. The CameraPreview widget shows the live camera feed once initialization is done.

The 'Take Photo' button calls _takePhoto() which uses the controller to capture a picture and saves it in _imageFile. We then display the captured photo below the button using Image.file.

We handle loading states with CircularProgressIndicator while the camera initializes. The UI updates reactively when a photo is taken.

This approach follows Flutter's camera package guidelines and ensures a smooth user experience.

Final Result
Completed Screen
┌─────────────────────────────┐
│        Camera Screen        │
├─────────────────────────────┤
│  [Live Camera Preview Here] │
│                             │
│                             │
│                             │
├─────────────────────────────┤
│  [Take Photo Button]         │
├─────────────────────────────┤
│  [Captured Photo Display]    │
│                             │
│                             │
└─────────────────────────────┘
User sees live camera preview filling top area
User taps 'Take Photo' button
App captures photo and displays it below the button
If no photo taken, text 'No photo taken yet' is shown
Stretch Goal
Add a button to switch between front and back cameras.
💡 Hint
Use the list of available cameras and update the CameraController with the selected camera index.