微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

防止 MTKView 相机源旋转,但允许其他屏幕上的 VC 旋转

如何解决防止 MTKView 相机源旋转,但允许其他屏幕上的 VC 旋转

目标

使用 MTKView,复制 AVCaptureVideoPreviewLayer 或 Apple 的相机应用程序的重力。视频设备方向不会改变。相机馈送的边缘不会移动一个像素,永远不会显示屏幕背景。其他屏幕上的 VC 正常旋转。

观察

viewWillTransition 期间应用 Tech QA 1890's transformMTKView 确实反向旋转......但该旋转仍然不舒服地可见。视图的边缘在动画过程中被取消固定,遮蔽了一些相机像素并显示为持有 MTKView 的 VC 设置的白色背景。

edges visible during rotation

问题

如何让这些边缘像受惊的蛤蜊一样粘在屏幕边界上?

我认为我的错误是由于限制,但我也愿意在其他方面犯错。 :)

查看层次结构

一个微型相机滤镜应用在固定到屏幕边缘的 MTKView(在 VC #2 中)之上有一个相机控件(VC #1)的叠加层。

UINavigationController
│ 
└─ CameraScreenVC
   │    
   ├── CameraControlsVC    <- Please rotate subviews
   │ 
   └── MetalCameraFeedVC
       └── MTKView         <- Please no rotation edges

代码

Buildable demo repo

以下相关片段。

MetalCameraVC.swift

final class MetalCameraVC: UIViewController {

    let mtkView = MTKView()    // This VC's only view

    /// Called in viewDidAppear
    func setupMetal(){
        MetalDevice = MTLCreateSystemDefaultDevice()
        mtkView.device = MetalDevice
        mtkView.isPaused = true
        mtkView.enableSetNeedsdisplay = false
        MetalCommandQueue = MetalDevice.makeCommandQueue()
        mtkView.delegate = self
        mtkView.framebufferOnly = false
        ciContext = CIContext(
            mtlDevice: MetalDevice,options: [.workingColorSpace: CGColorSpace(name: CGColorSpace.sRGB)!])
    }

    ...

    func mtkView(_ view: MTKView,drawableSizeWillChange size: CGSize) { 
         // blank 
    }

    func draw(in mtkview: MTKView) {
        
        image = image.transformed(by: scaletoScreenBounds)
        image = image.cropped(to: mtkview.drawableSize.zeroOriginRect())

        guard let buffer = MetalCommandQueue.makeCommandBuffer(),let currentDrawable = mtkview.currentDrawable
        else { return }
        
        ciContext.render(image,to: currentDrawable.texture,commandBuffer: buffer,bounds: mtkview.drawableSize.zeroOriginRect(),colorSpace: CGColorSpaceCreateDeviceRGB())
        
        buffer.present(currentDrawable)
        buffer.commit()
    }
}

extension MetalCameraVC {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(mtkView)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        mtkView.frame = view.frame

        if let orientation = AVCaptureVideoOrientation.fromCurrentDeviceOrientation() {
            lastOrientation = orientation
        }
    }
}

+旋转


/// Apple Technical QA 1890 Prevent View From Rotating
extension MetalCameraVC {
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        mtkView.center = CGPoint(x: view.bounds.midX,y: view.bounds.midY)
    }

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

        coordinator.animate { [self] context in

            let delta = coordinator.targetTransform
            let deltaAngle = atan2(delta.b,delta.a)
            var currentAngle = mtkView.layer.value(forKeyPath: "transform.rotation.z") as? CGFloat ?? 0
            currentAngle += -1 * deltaAngle + 0.1
            mtkView.layer.setValue(currentAngle,forKeyPath: "transform.rotation.z")

        } completion: { [self] context in

            var rounded = mtkView.transform
            rounded.a = round(rounded.a)
            rounded.b = round(rounded.b)
            rounded.c = round(rounded.c)
            rounded.d = round(rounded.d)
            mtkView.transform = rounded
        }
    }
    
}

解决方法

我认为“最简单”的解决方案实际上是阻止您的 UI 旋转并观察设备方向的变化,从而仅手动旋转您想要旋转的界面元素。

在您的视图控制器中,您可以覆盖 shouldAutorotate 以防止自动旋转并使用 supportedInterfaceOrientations 仅返回一个允许的方向。

可以使用其 transform 属性手动旋转 UI 元素。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。