panmari
panmari

Reputation: 3837

Consistent camera preview rotation behavior on phones and tablets in flutter

I'm struggling to have my app behave consistently on mobile and tablet. My goal is to have the camera preview rotate together with the device. Starting with the answer on this question, I created code to automatically rotate the camera preview to be aligned with the screen:

 NativeDeviceOrientationReader(builder: (context) {
            NativeDeviceOrientation orientation =
                NativeDeviceOrientationReader.orientation(context);
            // Works well for phones.
            int turns;
            switch (orientation) {
              case NativeDeviceOrientation.landscapeLeft:
                turns = 3;
                break;
              case NativeDeviceOrientation.landscapeRight:
                turns = 1;
                break;
              case NativeDeviceOrientation.portraitDown:
                turns = 2;
                break;
              default:
                turns = 0;
                break;
            }
            return RotatedBox(
              quarterTurns: turns,
              child: AspectRatio(
                aspectRatio: controller.value.aspectRatio,
                child: CameraPreview(controller),
              ),
            );
          }),

This works well for phones, which "natively" are in portrait mode (both the screen and camera). For my tablet (a Pixel C, if that matters) however, which is "natively" in landscape mode, I have to set the rotation behavior differently:

            // This works on a tablet, but not on a phone.
            switch (orientation) {
              case NativeDeviceOrientation.landscapeLeft:
                turns = 0;
                break;
              case NativeDeviceOrientation.landscapeRight:
                turns = 2;
                break;
              case NativeDeviceOrientation.portraitDown:
                turns = 1;
                break;
              default:
                turns = 3;
                break;
            }
        ...
        // Then also later:
        //  aspectRatio: 1 / controller.value.aspectRatio,

Is there a way to either

Note that I'm aware of alternative solution of just setting a preferred orientation:

SystemChrome.setPreferredOrientations([
  DeviceOrientation.portraitUp,
]);

This is a bad fit for my application, as I also have other content apart from the camera preview that needs to rotate together with the orientation.

Upvotes: 2

Views: 2838

Answers (1)

panmari
panmari

Reputation: 3837

I found a solution by reading out the camera controller's sensorOrientation. The phone reports there 90, while the tablet reports 0. Wrapping the camera preview in a rotated box, setting the rotation based on the readout, fixed the issue.

    RotatedBox(
      quarterTurns: 1 - controller.description.sensorOrientation ~/ 90,
      child: CameraPreview(controller),
    );

Upvotes: 3

Related Questions