AVCaptureVideoPreviewLayer横向

如何获得“AVCaptureVideoPreviewLayer”以横向显示正确显示? 它在纵向上工作正常,但不旋转,并且在父视图控制器处于横向方向时显示旋转的相机捕捉。

首先是答案

- (void)viewWillLayoutSubviews { _captureVideoPreviewLayer.frame = self.view.bounds; if (_captureVideoPreviewLayer.connection.supportsVideoOrientation) { _captureVideoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:[UIApplication sharedApplication].statusBarOrientation]; } } - (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; } 

我在这个问题上遇到了几个SOpost,找不到任何简单的解释,所以我想我会分享我自己的。

如果你关注Apple的样品,当你将iOS设备旋转到横向时,会遇到两个潜在的问题

  1. 捕捉将会出现旋转(就像您将相机保持90度closures一样)
  2. 它不会完全跨越其界限

这里的问题是,'CALayer'不支持自动旋转,因此,不像'UIView'你添加作为子视图,它不会旋转时,其父'UIView'旋转。 因此,每当父视图的边界发生更改( 不是父视图的帧,因为帧在旋转后保持不变 )时,您必须手动更新其框架。 这是通过覆盖容器视图控制器中的“viewWillLayoutSubviews”来实现的。

其次,你应该使用'videoOrientation'属性来告知AVFoundation有关的方向,以便正确预览。

希望这可以帮助。

Swift3

 func updateVideoOrientation() { guard let previewLayer = self.previewLayer else { return } guard previewLayer.connection.isVideoOrientationSupported else { print("isVideoOrientationSupported is false") return } let statusBarOrientation = UIApplication.shared.statusBarOrientation let videoOrientation: AVCaptureVideoOrientation = statusBarOrientation.videoOrientation ?? .portrait if previewLayer.connection.videoOrientation == videoOrientation { print("no change to videoOrientation") return } previewLayer.frame = cameraView.bounds previewLayer.connection.videoOrientation = videoOrientation previewLayer.removeAllAnimations() } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: nil, completion: { [weak self] (context) in DispatchQueue.main.async(execute: { self?.updateVideoOrientation() }) }) } 

 extension UIInterfaceOrientation { var videoOrientation: AVCaptureVideoOrientation? { switch self { case .portraitUpsideDown: return .portraitUpsideDown case .landscapeRight: return .landscapeRight case .landscapeLeft: return .landscapeLeft case .portrait: return .portrait default: return nil } } } 
 override func viewWillLayoutSubviews() { self.previewLayer.frame = self.view.bounds if previewLayer.connection.isVideoOrientationSupported { self.previewLayer.connection.videoOrientation = self.interfaceOrientation(toVideoOrientation: UIApplication.shared.statusBarOrientation) } } func interfaceOrientation(toVideoOrientation orientation: UIInterfaceOrientation) -> AVCaptureVideoOrientation { switch orientation { case .portrait: return .portrait case .portraitUpsideDown: return .portraitUpsideDown case .landscapeLeft: return .landscapeLeft case .landscapeRight: return .landscapeRight default: break } print("Warning - Didn't recognise interface orientation (\(orientation))") return .portrait } 

// SWIFT 3转换

除了viewWillLayoutSubviews(),你还必须实现didRotateFromInterfaceOrientation()。

这是因为如果设备从纵向模式转换到纵向模式(显然是出于效率原因),子视图布局将不会更新。