【问题标题】:Prevent UIView with AVCaptureVideoPreviewLayer from rotating with rest of ViewController防止带有 AVCaptureVideoPreviewLayer 的 UIView 与 ViewController 的其余部分一起旋转
【发布时间】:2019-01-22 05:59:57
【问题描述】:

我有一个视图控制器,嵌入在标签栏控制器中,除其他外,它在 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 只查看顶级视图控制器的这些属性。

根据我的所有尝试,视频预览与视图控制器的其余部分一起旋转 - 最终侧身。

唯一可行的,但很hacky,有时会导致视频预览错位,是这个

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 相机应用程序的行为相同,只是其他 UI 元素正常旋转而不是90°旋转变换)

【问题讨论】:

    标签: ios swift uiview uiviewcontroller avfoundation


    【解决方案1】:

    以下内容可能与您的解决方案一样老套,但在视觉上看起来更干净。

    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))) }
        }
    }
    

    【讨论】:

    • 我不确定您是否使用了过时的 CGAffineTransform 属性,或者我是否遗漏了某些内容,但我收到了 Value of type 'CGAffineTransform' has no member 'xScale'Value of type 'CGAffineTransform' has no member 'yScale' 设置 xScaleyScale 常量。我还得到了Value of type 'CGAffineTransform' has no member 'rotation'; did you mean 'rotated'?,您在其中声明了rotation 变量。我知道最近的 Swift 版本中 Core Graphics 库发生了一些变化,但我不知道如何在 Swift 4.2 中实现这一点。
    • 啊该死的忘了我写了一个 CGAffineTransform 的小扩展。我会把它添加到答案中
    猜你喜欢
    • 1970-01-01
    • 2014-10-27
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    • 2013-03-15
    相关资源
    最近更新 更多