对于 IOS16 的手机,当 iPhone 的方向发生变化时,AVfoundation PreviewLayer 的正确设置是什么?

问题描述 投票:0回答:1

我正在使用avfoundation制作一个录音应用程序,我的肖像效果很好,但每当我旋转时,预览也会旋转(当我的手机从肖像向右向右旋转时,“v”变成了“<').

我尝试使用 UIViewController 和 UIViewControllerRepresentable,我尝试将 updatePreviewLayerOrientation() 放在 viewDidLoad()、viewDidLayoutSubviews()、viewWillTransition() 中,但它们都不起作用。预览旋转并放大(我认为是由于resizeAspectFill)

class VideoPreviewView: UIView {
    
    override class var layerClass: AnyClass {
        return AVCaptureVideoPreviewLayer.self
    }
    
    var videoPreviewLayer: AVCaptureVideoPreviewLayer {
        return layer as! AVCaptureVideoPreviewLayer
    }
}

class CameraViewController: UIViewController {
    private var previewView = VideoPreviewView()

    override func viewDidLoad() {
        super.viewDidLoad()

        previewView.videoPreviewLayer.session = CameraManager.shared.session
        previewView.videoPreviewLayer.videoGravity = .resizeAspectFill
        previewView.videoPreviewLayer.frame = view.bounds
        view.layer.addSublayer(previewView.videoPreviewLayer)
        updatePreviewLayerOrientation
    }

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

    func updatePreviewLayerOrientation() {
        guard let connection = previewView.videoPreviewLayer.connection else { return }
        
        switch UIDevice.current.orientation {
        case .portrait:
            connection.videoOrientation = .portrait
        case .landscapeRight:
            connection.videoOrientation = .landscapeLeft
        case .landscapeLeft:
            connection.videoOrientation = .landscapeRight
        case .portraitUpsideDown:
            connection.videoOrientation = .portraitUpsideDown
        default:
            connection.videoOrientation = .portrait
        }
        
        previewView.videoPreviewLayer.frame = view.bounds
    }

然后我改为 UIViewRepresentable。我再次尝试在 updateUIView 中调用 updatePreviewLayerOrientation() ,但在 updateUIView 中不起作用。

struct CameraViewRepresentable: UIViewRepresentable {
    
    func makeUIView(context: Context) -> VideoPreviewView {
        let view = VideoPreviewView()
        view.backgroundColor = .black
        view.videoPreviewLayer.session = CameraManager.shared.session
        view.videoPreviewLayer.videoGravity = .resizeAspectFill
        CameraManager.shared.videoPreview = view
        
        return view
    }
    
    public func updateUIView(_ uiView: VideoPreviewView, context: Context) { }
    
    class VideoPreviewView: UIView {

       override class var layerClass: AnyClass {
          AVCaptureVideoPreviewLayer.self
       }
    
       var videoPreviewLayer: AVCaptureVideoPreviewLayer {
          return layer as! AVCaptureVideoPreviewLayer
       }
    }
}

我尝试编写一个 deideRotationModifier 并在那里更新方向,但不起作用。

struct DeviceRotationViewModifier: ViewModifier {
    let action: (UIDeviceOrientation) -> Void

    func body(content: Content) -> some View {
        content
            .onAppear()
            .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
                action(UIDevice.current.orientation)
            }
    }
}

// A View wrapper to make the modifier easier to use
extension View {
    func onRotate(perform action: @escaping (UIDeviceOrientation) -> Void) -> some View {
        self.modifier(DeviceRotationViewModifier(action: action))
    }
}

设置方向的正确方法是什么?

ios swift swiftui uikit avfoundation
1个回答
0
投票

我得到答案了!!!

class VideoPreviewView: UIView {

    override class var layerClass: AnyClass {
        return AVCaptureVideoPreviewLayer.self
    }

/// Convenience wrapper to get layer as its statically known type.
    var videoPreviewLayer: AVCaptureVideoPreviewLayer {
        return layer as! AVCaptureVideoPreviewLayer
    }
}

class CameraViewController: UIViewController {
    private var previewView = VideoPreviewView()

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let screenRect = UIScreen.main.bounds
        previewView.videoPreviewLayer.session = CameraManager.shared.session
        previewView.videoPreviewLayer.videoGravity = .resizeAspectFill
        previewView.videoPreviewLayer.frame = CGRect(x: 0, y: 0, width: screenRect.size.width, height: screenRect.size.height)
        previewView.videoPreviewLayer.connection?.videoOrientation = .portrait
        view.layer.addSublayer(previewView.videoPreviewLayer)
    }

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

    override func willTransition(to newCollection: UITraitCollection, with coordinator: any UIViewControllerTransitionCoordinator) {
        let screenRect = UIScreen.main.bounds
        previewView.videoPreviewLayer.frame = CGRect(x: 0, y: 0, width: screenRect.size.width, height: screenRect.size.height)
        updatePreviewLayerOrientation()
    }



    func updatePreviewLayerOrientation() {
        guard let connection = previewView.videoPreviewLayer.connection else { return }
    
        switch UIDevice.current.orientation {
        case .portrait:
            connection.videoOrientation = .portrait
        case .landscapeRight:
            connection.videoOrientation = .landscapeLeft
        case .landscapeLeft:
            connection.videoOrientation = .landscapeRight
        case .portraitUpsideDown:
            connection.videoOrientation = .portraitUpsideDown
        default:
            connection.videoOrientation = .portrait
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.