Toggling the flash modus on a Flutter camera

In the last blog post, I show how to take a picture in Flutter using the camera package. In this blog post, I will dive deeper into the camera by explaining how to turn the flash modus on and off!

I will start this example with the result of the previous blog post. In that blog post, I describe all steps necessary to show the camera’s preview and take a picture. One of the steps is to initialize the controller with the first camera. This controller has the following method to change the flash mode:

cameraController.setFlashMode(FlashMode.always);

There are different options to provide here. Besides on, and off there is also an option to set the flash mode to auto or torch. For my own example, I will toggle between the off and always modus.

/// The possible flash modes that can be set for a camera
enum FlashMode {
  /// Do not use the flash when taking a picture.
  off,

  /// Let the device decide whether to flash the camera when taking a picture.
  auto,

  /// Always use the flash when taking a picture.
  always,

  /// Turns on the flash light and keeps it on until switched off.
  torch,
}

So I know which method to call. Since I also want to change the icon, I will make the Widget a StatefulWidget. This way, I can change the icon after pressing the button. I provide the Widget with the controller directly, but it is also possible to provide the Widget with a Callback function.

The Widget is simply a button, and when the user presses the button I call the method to change the modus of the flash. Furthermore, I change the local variable to switch to a different icon. I did not find a way (yet) to extract the current flash modus from the controller. Otherwise, you could listen to the result of the setFlashMode before calling the setState method.

class CameraFlashWidget extends StatefulWidget {
  final CameraController cameraController;

  const CameraFlashWidget({Key? key, required this.cameraController}) : super(key: key);

  @override
  State<CameraFlashWidget> createState() => _CameraFlashWidgetState();
}

class _CameraFlashWidgetState extends State<CameraFlashWidget> {
  FlashMode flashMode = FlashMode.off;
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: FloatingActionButton(onPressed: () {
                setState(() {
                  if (flashMode == FlashMode.off) {
                    widget.cameraController.setFlashMode(FlashMode.always);
                    flashMode = FlashMode.always;
                  } else {
                    widget.cameraController.setFlashMode(FlashMode.off);
                    flashMode = FlashMode.off;
                  }
                });
              }, child: flashMode == FlashMode.off ? const Icon(Icons.flashlight_off) : const Icon(Icons.flashlight_on)),
            ),
          ],
        ),
      ],
    );
  }
}

Finally, all I need to do is to add the Widget in a Stacked Widget to make sure the button is visible above the preview. Another option is to make the preview smaller and change the placements of the buttons yourself.

Stack(
    children: [
      SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: CameraPreview(controller!),
      ),
      CameraFlashWidget(
        cameraController: controller,
      ),
    ],
  )

These steps are all that is necessary to change the flash modus of the camera! All of is this is possible thanks to the work of a lot of people on the camera package! The code of this example is available here on Github. If you still have any questions, comments, suggestions, remarks, please let me know!

Leave a Reply