66

我的应用程序仅是横向的。我正在展示这样的 AVCaptureVideoPreviewLayer:

self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
[self.previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
[self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];                    
NSLog(@"previewView: %@", self.previewView);
CALayer *rootLayer = [self.previewView layer];
[rootLayer setMasksToBounds:YES];
[self.previewLayer setFrame:[rootLayer bounds]];
    NSLog(@"previewlayer: %f, %f, %f, %f", self.previewLayer.frame.origin.x, self.previewLayer.frame.origin.y, self.previewLayer.frame.size.width, self.previewLayer.frame.size.height);
[rootLayer addSublayer:self.previewLayer];
[session startRunning];

self.previewView 的帧为 (0,0,568,320),这是正确的。self.previewLayer 记录一帧 (0,0,568,320),理论上是正确的。但是,相机显示在横向屏幕中间显示为纵向矩形,并且相机预览图像的方向错误 90 度。我究竟做错了什么?我需要相机预览层以全屏、横向模式出现,并且图像的方向应该正确。

4

19 回答 19

82

斯威夫特 5.5,Xcode 13.2

private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
    layer.videoOrientation = orientation
    self.previewLayer?.frame = view.bounds
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    if let connection = self.previewLayer?.connection {
        let currentDevice = UIDevice.current
        let orientation: UIDeviceOrientation = currentDevice.orientation
        let previewLayerConnection: AVCaptureConnection = connection
        
        if previewLayerConnection.isVideoOrientationSupported {
            switch orientation {
            case .portrait: self.updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
            case .landscapeRight: self.updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft)
            case .landscapeLeft: self.updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight)
            case .portraitUpsideDown: self.updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown)
            default: self.updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
            }
        }
    }
}

斯威夫特 2.2,Xcode 7.3

private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
    
    layer.videoOrientation = orientation

    previewLayer.frame = self.view.bounds

}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    if let connection =  self.previewLayer?.connection  {
        
        let currentDevice: UIDevice = UIDevice.currentDevice()
        
        let orientation: UIDeviceOrientation = currentDevice.orientation
        
        let previewLayerConnection : AVCaptureConnection = connection
        
        if (previewLayerConnection.supportsVideoOrientation) {
            
            switch (orientation) {
            case .Portrait: updatePreviewLayer(previewLayerConnection, orientation: .Portrait)
                                
            case .LandscapeRight: updatePreviewLayer(previewLayerConnection, orientation: .LandscapeLeft)
                                
            case .LandscapeLeft: updatePreviewLayer(previewLayerConnection, orientation: .LandscapeRight)
                                
            case .PortraitUpsideDown: updatePreviewLayer(previewLayerConnection, orientation: .PortraitUpsideDown)
                                
            default: updatePreviewLayer(previewLayerConnection, orientation: .Portrait)
            
            }
        }
    }
}
于 2016-04-12T13:54:35.083 回答
70

默认相机方向是向左横向(左侧一个主页按钮)。你需要在这里做两件事:

1-将 previewLayer 框架更改为:

self.previewLayer.frame=self.view.bounds;

您需要将预览层框架设置为屏幕的边界,以便在屏幕旋转时预览层的框架会发生变化(您不能使用根视图的框架,因为它不会随旋转而改变,而是根视图的边界做)。在您的示例中,您将 previewlayer 框架设置为我没有看到的 previewView 属性。

2-您需要随着设备的旋转而旋转预览层连接。在 viewDidAppear 中添加此代码:

-(void) viewDidAppear:(BOOL)animated
{
  [super viewDidAppear:YES];

  //Get Preview Layer connection
  AVCaptureConnection *previewLayerConnection=self.previewLayer.connection;

  if ([previewLayerConnection isVideoOrientationSupported])
    [previewLayerConnection setVideoOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; 
}

希望这能解决它。

完全披露:这是一个简化版本,因为您不在乎横向或横向。

于 2013-02-25T20:33:16.563 回答
30
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    if let connection = self.previewLayer?.connection {
        let currentDevice: UIDevice = UIDevice.current
        let orientation: UIDeviceOrientation = currentDevice.orientation
        let previewLayerConnection : AVCaptureConnection = connection
        
        if (previewLayerConnection.isVideoOrientationSupported) {
            switch (orientation) {
            case .portrait:
                previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portrait
            case .landscapeRight:
                previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.landscapeRight
            case .landscapeLeft:
                previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
            case .portraitUpsideDown:
                previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
                
            default:
                previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.portrait
            }
        }
    }
}
于 2015-10-11T01:12:51.573 回答
23

API 似乎发生了一些变化。videoOrientation现在是预览图层属性的一个connection属性。此外,无需使用开关。Swift 3.0 的答案:

override func viewDidLayoutSubviews() {
    self.configureVideoOrientation()
}

private func configureVideoOrientation() {
    if let previewLayer = self.previewLayer,
        let connection = previewLayer.connection {
        let orientation = UIDevice.current.orientation

        if connection.isVideoOrientationSupported,
            let videoOrientation = AVCaptureVideoOrientation(rawValue: orientation.rawValue) {
            previewLayer.frame = self.view.bounds
            connection.videoOrientation = videoOrientation
        }
    }
}
于 2017-08-25T05:23:44.833 回答
19

我们不能使用

[previewLayerConnection setVideoOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; 

因为UIInterfaceOrientation != AVCaptureVideoOrientation

但是我们可以只测试值......并且这项工作,使用以下代码。

-(void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    switch (orientation) {
        case UIInterfaceOrientationPortrait:
            [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
            break;
        case UIInterfaceOrientationLandscapeLeft:
            [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
            break;
        case UIInterfaceOrientationLandscapeRight:
            [_videoPreviewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
            break;
    }
}
于 2015-05-13T14:23:29.470 回答
7

对于任何在全功能相机预览上苦苦挣扎的人。这是生产代码。当然,缺点是方向改变时会出现滞后。如果有人有更好的解决方案来克服这个问题,请分享

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self initCamera];
}

- (void)initCamera
{
    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil];
    if (captureInput) {
        mSession = [[AVCaptureSession alloc] init];
        [mSession addInput:captureInput];
    }
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    if ([mSession isRunning]) {
        [mSession stopRunning];
        [mCameraLayer removeFromSuperlayer];

        [self initCamera];

        [self startCamera];
    }
}

- (void)startCamera
{
    [mSession startRunning];
    Settings::getInstance()->setClearColor(Color(0, 0, 0, 0));
    mCameraLayer = [AVCaptureVideoPreviewLayer layerWithSession: mSession];
    [self updateCameraLayer];
    [mCameraView.layer addSublayer:mCameraLayer];
}

- (void)stopCamera
{
    [mSession stopRunning];
    [mCameraLayer removeFromSuperlayer];
    Settings::getInstance()->setDefClearColor();
}

- (void)toggleCamera
{
    mSession.isRunning ? [self stopCamera] : [self startCamera];
    [mGLKView setNeedsDisplay];
}

- (void)updateCameraLayer
{
    mCameraLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    mCameraLayer.frame = mCameraView.bounds;
    float x = mCameraView.frame.origin.x;
    float y = mCameraView.frame.origin.y;
    float w = mCameraView.frame.size.width;
    float h = mCameraView.frame.size.height;
    CATransform3D transform = CATransform3DIdentity;
    if (UIDeviceOrientationLandscapeLeft == [[UIDevice currentDevice] orientation]) {
        mCameraLayer.frame = CGRectMake(x, y, h, w);
        transform = CATransform3DTranslate(transform, (w - h) / 2, (h - w) / 2, 0);
        transform = CATransform3DRotate(transform, -M_PI/2, 0, 0, 1);
    } else if (UIDeviceOrientationLandscapeRight == [[UIDevice currentDevice] orientation]) {
        mCameraLayer.frame = CGRectMake(x, y, h, w);
        transform = CATransform3DTranslate(transform, (w - h) / 2, (h - w) / 2, 0);
        transform = CATransform3DRotate(transform, M_PI/2, 0, 0, 1);
    } else if (UIDeviceOrientationPortraitUpsideDown == [[UIDevice currentDevice] orientation]) {
        mCameraLayer.frame = mCameraView.bounds;
        transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
    } else {
        mCameraLayer.frame = mCameraView.bounds;
    }
    mCameraLayer.transform  = transform;
}

    enter code here
于 2014-03-14T01:23:56.940 回答
4

由于使用上述解决方案存在弃用和转换警告,并且在 iOS7 中设置 videoOrientation 似乎不起作用,因此我在 AVCaptureVideoPreviewLayer 的 getter 中检查方向,如下所示:

- (AVCaptureVideoPreviewLayer *) previewLayer
{
    if(!_previewLayer)
    {
        _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession: self.captureSession];

    [_previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

    _previewLayer.frame = self.view.bounds; // Assume you want the preview layer to fill the view.

    [_previewLayer setPosition:CGPointMake(0,0)];

    if (UIDeviceOrientationLandscapeLeft == [[UIDevice currentDevice] orientation]) {
        _previewLayer.transform = CATransform3DMakeRotation(-M_PI/2, 0, 0, 1);
    }
    else if (UIDeviceOrientationLandscapeRight == [[UIDevice currentDevice] orientation])
    {
        _previewLayer.transform = CATransform3DMakeRotation(M_PI/2, 0, 0, 1);
    }
}

return _previewLayer;
}
于 2013-12-17T22:28:13.460 回答
4

斯威夫特 5 版本

  override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    updatePreview()
  }

  func updatePreview() {
    let orientation: AVCaptureVideoOrientation
    switch UIDevice.current.orientation {
      case .portrait:
        orientation = .portrait
      case .landscapeRight:
        orientation = .landscapeLeft
      case .landscapeLeft:
        orientation = .landscapeRight
      case .portraitUpsideDown:
        orientation = .portraitUpsideDown
      default:
        orientation = .portrait
    }
    if previewLayer?.connection?.isVideoOrientationSupported == true {
      previewLayer?.connection?.videoOrientation = orientation
    }
    previewLayer.frame = view.bounds
  }
于 2019-04-03T13:27:53.070 回答
3

适用于 Swift 4、Xcode 9:

  override func viewWillTransition(to size: CGSize,
                                   with coordinator: UIViewControllerTransitionCoordinator)
  {
    super.viewWillTransition(to: size, with: coordinator)
    guard
    let conn = self.previewLayer?.connection,
      conn.isVideoOrientationSupported
      else { return }
    let deviceOrientation = UIDevice.current.orientation
    switch deviceOrientation {
    case .portrait: conn.videoOrientation = .portrait
    case .landscapeRight: conn.videoOrientation = .landscapeLeft
    case .landscapeLeft: conn.videoOrientation = .landscapeRight
    case .portraitUpsideDown: conn.videoOrientation = .portraitUpsideDown
    default: conn.videoOrientation = .portrait
    }
  }

这里要注意的一个微妙之处是UIDeviceOrientation.landscapeRightAVCaptureVideoOrientation.landscapeLeft.

另一个景观案例同样不匹配。这是故意的,并适应了 UIKit 和 AVFoundation 之间不幸的不匹配。如果您通过匹配名称来匹配案例,它将不起作用,并且您的视频将在横向配置中颠倒。

于 2017-11-14T05:11:39.453 回答
3

适用于 Swift 4.2 - Xcode 10.0 - iOS 12.0 的选定答案:

var videoPreviewLayer: AVCaptureVideoPreviewLayer?

override func viewDidLayoutSubviews() {
  super.viewDidLayoutSubviews()
  if let previewLayerConnection =  self.videoPreviewLayer?.connection, previewLayerConnection.isVideoOrientationSupported {
    updatePreviewLayer(layer: previewLayerConnection, orientation: UIApplication.shared.statusBarOrientation.videoOrientation)
  }
}

private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {
  layer.videoOrientation = orientation
  videoPreviewLayer?.frame = self.view.bounds
}

不要忘记从 UIInterfaceOrientation 到 AVCaptureVideoOrientation 的映射

extension UIInterfaceOrientation {

  public var videoOrientation: AVCaptureVideoOrientation {
    switch self {
    case .portrait:
      return AVCaptureVideoOrientation.portrait
    case .landscapeRight:
      return AVCaptureVideoOrientation.landscapeRight
    case .landscapeLeft:
      return AVCaptureVideoOrientation.landscapeLeft
    case .portraitUpsideDown:
      return AVCaptureVideoOrientation.portraitUpsideDown
    default:
      return AVCaptureVideoOrientation.portrait
    }
  }

}
于 2018-08-09T09:50:29.273 回答
3

UIDeviceOrientation正确的从to映射AVCaptureVideoOrientation是必要的。

如果您的应用支持device rotation,resizing preview.frame也是必需的,这func应该从viewDidLayoutSubviews()和调用viewWillTransition()

private func configureVideoOrientation() {
    if let preview = self.previewLayer,
        let connection = preview.connection {
        let orientation = UIDevice.current.orientation

        if connection.isVideoOrientationSupported {
            var videoOrientation: AVCaptureVideoOrientation
            switch orientation {
            case .portrait:
                videoOrientation = .portrait
            case .portraitUpsideDown:
                videoOrientation = .portraitUpsideDown
            case .landscapeLeft:
                videoOrientation = .landscapeRight
            case .landscapeRight:
                videoOrientation = .landscapeLeft
            default:
                videoOrientation = .portrait
            }
            preview.frame = self.view.bounds
            connection.videoOrientation = videoOrientation
        }
    }
}
于 2018-09-10T07:19:56.843 回答
2

嘿,伙计们,感谢您对此的所有答案和反馈,我在开发 swift 应用程序时遇到了这个问题。您可以使用以下代码实现相机随设备旋转:

override func shouldAutorotate() -> Bool {
        if your cameraController.previewLayer.connection != nil {
            var currentDevice: UIDevice = UIDevice.currentDevice()
            var orientation: UIDeviceOrientation = currentDevice.orientation

            var previewLayerConnection : AVCaptureConnection = your cameraController.previewLayer.connection

            if (previewLayerConnection.supportsVideoOrientation)
            {
                switch (orientation)
                {
                case .Portrait:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
                    break
                case .LandscapeRight:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeLeft
                    break
                case .LandscapeLeft:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeRight
                    break
                default:
                    previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
                    break
                }
            }

        }
        return true
    }

希望这可以帮助!

于 2015-09-10T16:03:20.573 回答
1

首先我们需要创建 AVCaptureVideoPreviewLayer 和:

  1. 设置它的videoGravity(在我的例子中,我使用一个小视图来获取视频输出)。
  2. 设置框架。

    [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [_videoPreviewLayer setFrame:_viewPreview.layer.bounds];
    
  3. 最初设置方向

    if (_videoPreviewLayer.connection.supportsVideoOrientation) {
            _videoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:[UIApplication sharedApplication].statusBarOrientation];
        }
  4. 使用简单的 switch case 为每个 case 设置方向

    -(AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation:

    (UIInterfaceOrientation)orientation {
    
        switch (orientation) {
            case UIInterfaceOrientationPortrait:
                return AVCaptureVideoOrientationPortrait;
            case UIInterfaceOrientationPortraitUpsideDown:
                return AVCaptureVideoOrientationPortraitUpsideDown;
            case UIInterfaceOrientationLandscapeLeft:
                return AVCaptureVideoOrientationLandscapeLeft ;
            case UIInterfaceOrientationLandscapeRight:
                return AVCaptureVideoOrientationLandscapeRight;
            default:
                break;
        }
        NSLog(@"Warning - Didn't recognise interface orientation (%d)",orientation);
        return AVCaptureVideoOrientationPortrait;
    

    }

  5. 由于设备同时支持landscapeLeft 和landscapeRight,因此使用调用旋转的委托:
    - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
    if (_videoPreviewLayer.connection.supportsVideoOrientation) {
        _videoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:toInterfaceOrientation];
     }
    }
    
于 2015-10-01T07:31:47.210 回答
1

我也面临同样的问题这是为了修复我的相机方向

override func shouldAutorotate() -> Bool {
        return false
    }

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
        return UIInterfaceOrientation.LandscapeLeft
    }

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.LandscapeLeft
    }

固定相机

let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.avCaptureSession)    
previewLayer.frame = self.view.layer.frame
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
于 2017-08-05T10:18:10.117 回答
1

Maselko 的回答几乎对我有用,除了如果状态栏方向翻转,则相机输出显示颠倒。我已经通过在状态栏翻转时重新调用 Maselko 的逻辑来解决这个问题。

这是我修改后的 Maselko 解决方案(在 ios12/swift4 上测试):

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    setCameraOrientation()
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    setCameraOrientation()
}

@objc func setCameraOrientation() {
    if let connection =  self.previewLayer?.connection  {
        let currentDevice: UIDevice = UIDevice.current
        let orientation: UIDeviceOrientation = currentDevice.orientation
        let previewLayerConnection : AVCaptureConnection = connection
        if previewLayerConnection.isVideoOrientationSupported {
            let o: AVCaptureVideoOrientation
            switch (orientation) {
            case .portrait: o = .portrait
            case .landscapeRight: o = .landscapeLeft
            case .landscapeLeft: o = .landscapeRight
            case .portraitUpsideDown: o = .portraitUpsideDown
            default: o = .portrait
            }

            previewLayerConnection.videoOrientation = o
            previewLayer!.frame = self.view.bounds
        }
    }
}
于 2018-07-06T22:05:47.710 回答
1

Maselko答案的改进版本

效果很好!

override func viewDidLayoutSubviews() {
  super.viewDidLayoutSubviews()
  if let connection =  previewView.connection  {
    if connection.isVideoOrientationSupported {
      let videoOrientation = AVCaptureVideoOrientation.init(rawValue: UIApplication.shared.statusBarOrientation.rawValue)!
      connection.videoOrientation = videoOrientation
      previewView.frame = self.view.bounds
    }
  }
}
于 2019-04-11T07:52:32.933 回答
0

它在 iOS 8 到 11.1 中为我工作而没有任何问题的唯一方法是这样做,我应该提到,在我的情况下,我只在横向模式下加载了我的应用程序,但它应该在所有方向上工作。(顺便说一句,你可以覆盖通过imageview手动相机或任何你想要的东西很容易)

@interface ViewController (){
    AVCaptureVideoPreviewLayer * previewLayer;
    AVCaptureSession* session;
}
@property (weak, nonatomic) IBOutlet UIView *cameraPreviewView;


-(void)viewDidLoad{
    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:nil];
    if (captureInput) {
        session = [[AVCaptureSession alloc] init];
        [session addInput:captureInput];
    }
    previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect];

    CALayer *rootLayer = [self.cameraPreviewView layer];
    [rootLayer setMasksToBounds:YES];
    [previewLayer setFrame:[self.view bounds]];
    [rootLayer addSublayer:previewLayer];
    [session startRunning];

    //Orientation Code is in viewDidLayoutSubviews method
}
-(void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    switch (orientation) {
        case UIInterfaceOrientationPortrait:
            [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
            break;
        case UIInterfaceOrientationLandscapeLeft:
            [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
            break;
        case UIInterfaceOrientationLandscapeRight:
            [previewLayer.connection setVideoOrientation:AVCaptureVideoOrientationLandscapeRight];
            break;
        default:break;
    }
}
于 2017-11-06T20:44:32.793 回答
0

@Maselko 的答案是正确的,但有一件事:您应该使用UIApplication.shared.statusBarOrientation而不是UIDevice.current.orientation,因为设备方向是您的设备物理定位的方式。当您的设备处于横向但您的 UI 不支持该方向时,它会中断(例如,当我制作仅限横向的相机应用程序并在设备处于纵向位置时启动视图时)。

private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) {

    layer.videoOrientation = orientation

    previewLayer.frame = self.view.bounds

}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if let connection =  self.previewLayer?.connection  {

        let currentDevice: UIDevice = UIDevice.current

        let orientation = UIApplication.shared.statusBarOrientation

        let previewLayerConnection : AVCaptureConnection = connection

        if previewLayerConnection.isVideoOrientationSupported {

            switch (orientation) {
            case .portrait: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)

                break

            case .landscapeRight: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft)

                break

            case .landscapeLeft: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight)

                break

            case .portraitUpsideDown: updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown)

                break

            default: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)

                break
            }
        }
    }
}
于 2018-06-28T05:49:22.930 回答
0

这是我在 Swift 4 中使用的解决方案。

它很短,对我来说效果很好。

open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    let videoLayer = self.previewLayer
    coordinator.animate(alongsideTransition: { (context: UIViewControllerTransitionCoordinatorContext) in

        guard let connection = videoLayer?.connection, connection.isVideoOrientationSupported, let orientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue) else {
            return
        }

        connection.videoOrientation = orientation
        videoLayer?.frame = self.view.bounds

    }) { (context: UIViewControllerTransitionCoordinatorContext) in
        // handle any completion logic here...
    }
}
于 2018-08-09T17:26:58.287 回答