防止带有AVCaptureVideoPreviewLayer的UIView与其他ViewController一起旋转

时间:2019-01-22 05:59:58

标签: ios swift uiview uiviewcontroller avfoundation

我有一个嵌入在标签栏控制器中的视图控制器,除其他功能外,它还可以在UIView中呈现AVCaptureVideoPreviewLayer。

旋转设备时,我希望视图控制器随其旋转-除了上述UIView。

但是,与this related question不同,我不只是在视图控制器中旋转/变换其他视图。其他视图需要使用其配置的自动布局旋转行为。

我尝试了几件事,包括简单地将视频方向设置为纵向:

previewLayer.connection.videoOrientation = .portrait

将UIView提取到单独的视图控制器,将该视图控制器嵌入到原始视图控制器中,并设置其autoRotation属性

override var shouldAutorotate: Bool {
    return false
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

但是后来我了解到here,iOS仅查看这些属性的顶级视图控制器。

使用我尝试过的所有方法,视频预览都与视图控制器的其余部分一起旋转-侧向结束。

这是唯一可行的方法,但是它很笨拙,有时会导致视频预览无法对齐

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

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        if let videoPreviewLayerConnection = previewLayer.connection {
            if let newVideoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue) {
                videoPreviewLayerConnection.videoOrientation = newVideoOrientation
            }
        }
    }
}

我基本上需要与this question相反。

如何强制视频预览不旋转,但又允许视图控制器的其余部分正常旋转?(与iOS Camera应用程序的行为相同,只是其他UI元素正常旋转而不是旋转90°旋转变换)

1 个答案:

答案 0 :(得分:0)

以下内容可能与您的解决方案一样棘手,但外观看上去更清晰。

viewWillTransition中,我设置了PreviewView的仿射变换,以抵消通过旋转手机设置的方向。它看起来比仅设置videoOrientation更为干净,因为仿射变换的动画制作速度与方向变化相同。操作如下。

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

    let orientation = UIDevice.current.orientation
    var rotation : CGFloat = self.previewView.transform.rotation
    switch(orientation) {
    case .portrait:
        rotation = 0.0
    case .portraitUpsideDown:
        rotation = CGFloat.pi
    case .landscapeLeft:
        rotation = -CGFloat.pi/2.0
    case .landscapeRight:
        rotation = CGFloat.pi/2.0
    default:
        break
    }
    let xScale = self.previewView.transform.xScale
    let yScale = self.previewView.transform.yScale
    self.previewView.transform = CGAffineTransform(scaleX:xScale, y:yScale).rotated(by:rotation)
    self.view.layoutIfNeeded()

}

这是CGAffineTransform上面代码使用的扩展

extension CGAffineTransform {
    public var xScale: CGFloat {
        get {return sqrt(self.a * self.a + self.c * self.c) }
    }
    public var yScale: CGFloat {
        get {return sqrt(self.b * self.b + self.d * self.d) }
    }
    public var rotation: CGFloat {
        get {return CGFloat(atan2f(Float(self.b), Float(self.a))) }
    }
}