简体   繁体   English

Flutter Camera Preview 不随手机方向旋转

[英]Flutter Camera Preview not rotating with phone orientation

I'm new to Dart/Flutter and currently using the Flutter Camera Plugin but I am running into a problem with the CameraPreview for when the phone turns to landscape mode.我是 Dart/Flutter 的新手,目前正在使用 Flutter 相机插件,但是当手机转到横向模式时,我遇到了 CameraPreview 的问题。 The images stay vertical and don't rotate the 90degrees with the phone.图像保持垂直,不要用手机旋转 90 度。

I have tried countless things including Transform.rotate(), but I can't seem to get the image to both, fill the screen and rotate 90degrees.我尝试了无数的事情,包括 Transform.rotate(),但我似乎无法同时获得图像,填充屏幕并旋转 90 度。

The pictures that were taken while the phone was sideways still saved in the correct orientation when I view them, but using the _cameraPreviewWidget.当我查看时,手机侧身拍摄的照片仍然以正确的方向保存,但使用 _cameraPreviewWidget。

Normal普通的

Landscape风景

When you rotate your phone while using a camera the preview will stay vertical, however when you view the image it will be in landscape, try with the default camera app and it would be the same 当您在使用相机的同时旋转手机时,预览将保持垂直,但是当您查看图像时,它将处于横向状态,尝试使用默认的相机应用程序,它将是相同的

You can obviously rotate your UI that is on top of the camera preview when the phone rotates 显然,当手机旋转时,您可以旋转相机预览顶部的UI

A package call camera_camera https://pub.dev/packages/camera_camera 打包电话camera_camera https://pub.dev/packages/camera_camera
has do great work and provide great feature you can reference his source code or fork directly. 做了很棒的工作,并提供了很好的功能,你可以直接参考他的源代码或分叉。

about rotate issue, please use this package https://pub.dev/packages/native_device_orientation 关于旋转问题,请使用此包https://pub.dev/packages/native_device_orientation
and wrap body like this 并像这样包裹身体

return Scaffold(
      body: NativeDeviceOrientationReader(builder: (context) {
        NativeDeviceOrientation orientation =
            NativeDeviceOrientationReader.orientation(context);

you can reference full code at https://github.com/marslord/camera/blob/master/lib/cam.dart ,this is not camera_camera package and author use RotateBox 你可以在https://github.com/marslord/camera/blob/master/lib/cam.dart上引用完整的代码,这不是camera_camera包,作者使用RotateBox

return RotatedBox(
          quarterTurns: turns,
          child: Transform.scale(
            scale: 1 / controller.value.aspectRatio,
            child: Center(
              child: AspectRatio(
                aspectRatio: controller.value.aspectRatio,
                child: CameraPreview(controller),
              ),
            ),
          ),
        );

camera_camera package use this at line 76 camera_camera包在76行使用它

return NativeDeviceOrientationReader(
  useSensor: true,
  builder: (context) {
    NativeDeviceOrientation orientation =
        NativeDeviceOrientationReader.orientation(context);

about fit screen issue 关于合适的屏幕问题
camera_camera package do this with below code full code is here https://github.com/gabuldev/camera_camera/blob/master/lib/page/camera.dart camera_camera包使用下面的代码执行此操作完整代码在这里https://github.com/gabuldev/camera_camera/blob/master/lib/page/camera.dart

    return widget.mode ==
              CameraMode.fullscreen
          ? OverflowBox(
              maxHeight: size.height,
              maxWidth: size.height *
                  previewRatio,
              child: CameraPreview(
                  bloc.controllCamera),
            )
          : AspectRatio(
              aspectRatio: bloc
                  .controllCamera
                  .value
                  .aspectRatio,
              child: CameraPreview(
                  bloc.controllCamera),
            );

execute result of camera_camera package can found on his github 执行camera_camera包的结果可以在他的github上找到

execute result of https://github.com/marslord/camera 执行https://github.com/marslord/camera的结果
在此输入图像描述

both check with real device and works 检查真实设备和工作

official camera plugin example rotate image can work with combine Native_device_orientation and RotateBox , you can reference https://github.com/marslord/camera/blob/master/lib/cam.dart 官方相机插件示例旋转图像可以与Native_device_orientation和RotateBox结合使用,可以参考https://github.com/marslord/camera/blob/master/lib/cam.dart
but official camera plugin example fit screen issue will need to modify layout code 但官方相机插件示例适合屏幕问题将需要修改布局代码

I would suggest use camera_camera's method, Stack CameraPreview and Button. 我建议使用camera_camera的方法,Stack CameraPreview和Button。 it looks more like Native Camera App and easy to maintain landscape mode 它看起来更像Native Camera App并且易于维护横向模式

official camera plugin example rotate image code snippet with combine Native_device_orientation and RotateBox 官方相机插件示例旋转图像代码片段,结合Native_device_orientation和RotateBox

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: const Text('Camera example'),
      ),
      body: NativeDeviceOrientationReader(builder: (context) {

        NativeDeviceOrientation orientation =
        NativeDeviceOrientationReader.orientation(context);

        int turns;
        switch (orientation) {
          case NativeDeviceOrientation.landscapeLeft:
            turns = -1;
            break;
          case NativeDeviceOrientation.landscapeRight:
            turns = 1;
            break;
          case NativeDeviceOrientation.portraitDown:
            turns = 2;
            break;
          default:
            turns = 0;
            break;
        }

        return Column(
          children: <Widget>[
            Expanded(
              child: RotatedBox(
                quarterTurns: turns,
                child: Transform.scale(
                  scale: 1 / controller.value.aspectRatio,
                  child: Container(
                    child: Padding(
                      padding: const EdgeInsets.all(1.0),
                      child: AspectRatio(
                        aspectRatio: controller.value.aspectRatio,
                        child: Center(
                          child: _cameraPreviewWidget(),
                        ),
                      ),
                    ),

Adding SystemChrome.setPreferredOrientations() to my initState() & dispose() functions solved this problem for me. SystemChrome.setPreferredOrientations()添加到我的initState()和dispose()函数为我解决了这个问题。

  import 'package:flutter/services.dart';

  ...

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

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

  @override
  void dispose() {
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeRight,
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ]);
  }

In my case, a real Android device in Landscape orientation would show the appropriate camera preview content, but because the device wasn't "allowed" to rotate (due to app manifest/plist settings), it was showing as a strip where the Left to Right wide pixels were showing in a rectangle on the left side going from Bottom to Top, where that rectangle was small in order to fit in that dimension... so most of the screen was white empty space.在我的情况下,横向的真实 Android 设备会显示适当的相机预览内容,但由于设备未被“允许”旋转(由于应用清单/plist 设置),它显示为条带,其中左侧到右侧的宽像素显示在左侧的矩形中,从底部到顶部,该矩形很小以适合该尺寸......所以大部分屏幕都是白色的空白空间。 On emulators, this phenomenon didn't occur (rotation worked as desired).在模拟器上,没有发生这种现象(旋转按预期工作)。 The solution, after much searching and troubleshooting was to put some code in to modify what orientations were allowed, only while the camera preview was being displayed:经过大量搜索和故障排除后,解决方案是放入一些代码来修改允许的方向,仅在显示相机预览时:

//allows any rotation (while camera preview is open)
Future<void> _enableRotation() async {
  await SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown,
    DeviceOrientation.landscapeLeft,
    DeviceOrientation.landscapeRight,
  ]);
}

// may block rotation; sets orientation back to OS defaults for the app
Future<void> _backToOriginalRotation() async {
  await SystemChrome.setPreferredOrientations([]);
}

I used await _enableRotation();我使用了await _enableRotation(); in initializing an ancestor of CameraPreview and I used await _backToOriginalRotation();在初始化CameraPreview的祖先时,我使用了await _backToOriginalRotation(); in disposing.在处置。 I used WillPopScope 's onWillPop callback and await Navigator.of(context).maybePop<String>>(filepath);我使用WillPopScopeonWillPop回调并await Navigator.of(context).maybePop<String>>(filepath); to close the view when a picture had been captured (and after the image had been saved to temp directory at the path filepath ), so that the Android back button would also run the dispose and rotation code via onWillPop .在捕获图片时关闭视图(并且在图像已保存到路径filepath临时目录之后),以便 Android 后退按钮也将通过onWillPop运行处置和旋转代码。

EDIT: After testing on both iOS and Android actual devices, this fix worked on Android phones, but did not work on iPhones.编辑:在 iOS 和 Android 实际设备上进行测试后,此修复程序适用于 Android 手机,但不适用于 iPhone。 iPhones still displayed the camera preview in a small rotated strip when the device is landscape.当设备处于横向时,iPhone 仍会在一个小的旋转条中显示相机预览。 This is using camera package version 0.8.1+7 .这是使用相机包版本0.8.1+7

My solution;我的解决方案; using with this libraries;与这个库一起使用; https://pub.dev/packages/image and https://pub.dev/packages/native_device_orientation https://pub.dev/packages/imagehttps://pub.dev/packages/native_device_orientation

 Future<void> takeAPicture()async{
pictureShooting=true;
final XFile image=await cameraController!.takePicture();
img.Image? _capturedImage=img.decodeImage(await image.readAsBytes());

final NativeDeviceOrientation currentOrientation=await _nativeDeviceOrientationCommunicator.orientation(useSensor: true);

switch(currentOrientation){
  case NativeDeviceOrientation.landscapeRight: _capturedImage=img.copyRotate(_capturedImage!, 90);break;
  case NativeDeviceOrientation.landscapeLeft:   _capturedImage=img.copyRotate(_capturedImage!, 270);break;
  case NativeDeviceOrientation.portraitDown:   _capturedImage=img.copyRotate(_capturedImage!, 180);break;
  default:
}

takenImage=Uint8List.fromList(img.encodePng(_capturedImage!));

pictureShooting=false;
showImageApprovalScreen=true;

} }

class _VideoPlayerWidgetState extends State<VideoPlayerWidget> {
  VideoPlayerController _videoPlayerController;
  ChewieController _chewieController;

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

  Future<void> initializePlayer() async {
// widget.url put url video file path
    _videoPlayerController =
        _videoPlayerController = VideoPlayerController.network(widget.url);
    await Future.wait([_videoPlayerController.initialize()]);
    _chewieController = ChewieController(
      videoPlayerController: _videoPlayerController,
      autoPlay: true,
      looping: true,
    );
  }

  bool useSensor = true;
  bool portrait;

 
  @override
  Widget build(BuildContext context) {
    return NativeDeviceOrientationReader(
      builder: (context) {
        NativeDeviceOrientation orientation =
            NativeDeviceOrientationReader.orientation(context);
        portrait = orientation == NativeDeviceOrientation.portraitUp;
        if(orientation == NativeDeviceOrientation.landscapeLeft){
          SystemChrome.setPreferredOrientations([
            !portrait
                ? DeviceOrientation.landscapeLeft
                : DeviceOrientation.portraitUp,
            !portrait
                ? DeviceOrientation.landscapeLeft
                : DeviceOrientation.portraitDown,
          ]);

        }else{
          SystemChrome.setPreferredOrientations([
            !portrait
                ? DeviceOrientation.landscapeRight
                : DeviceOrientation.portraitUp,
            !portrait
                ? DeviceOrientation.landscapeRight
                : DeviceOrientation.portraitDown,
          ]);
        }
        return _chewieController != null &&
                _chewieController.videoPlayerController.value.isInitialized
            ? Chewie(
                controller: _chewieController,
              )
            : Center(child: CircularProgressIndicator());
      },
      useSensor: useSensor,
    );
  }

  @override
  void dispose() {
    _videoPlayerController.dispose();
    _chewieController.dispose();
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    super.dispose();
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM