如何解决防止 MTKView 相机源旋转,但允许其他屏幕上的 VC 旋转
目标
使用 MTKView,复制 AVCaptureVideoPreviewLayer 或 Apple 的相机应用程序的重力。视频设备方向不会改变。相机馈送的边缘不会移动一个像素,永远不会显示屏幕背景。其他屏幕上的 VC 正常旋转。
观察
在 viewWillTransition
期间应用 Tech QA 1890's transform,MTKView
确实反向旋转......但该旋转仍然不舒服地可见。视图的边缘在动画过程中被取消固定,遮蔽了一些相机像素并显示为持有 MTKView 的 VC 设置的白色背景。
问题
如何让这些边缘像受惊的蛤蜊一样粘在屏幕边界上?
我认为我的错误是由于限制,但我也愿意在其他方面犯错。 :)
查看层次结构
一个微型相机滤镜应用在固定到屏幕边缘的 MTKView(在 VC #2 中)之上有一个相机控件(VC #1)的叠加层。
UINavigationController
│
└─ CameraScreenVC
│
├── CameraControlsVC <- Please rotate subviews
│
└── MetalCameraFeedVC
└── MTKView <- Please no rotation edges
代码
以下相关片段。
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 举报,一经查实,本站将立刻删除。