使用 AVFoundation 旋转 UIViewRepresentable View
Rotation of UIViewRepresentable View using AVFoundation
我正在使用 CameraPreview
(UIViewRepresentable
) 作为 UIKit
和 SwiftUI
之间的桥梁。 CameraPreview
配置为CameraModel
,使用AVCaptureVideoPreviewLayer
。 CameraModel
正在配置 AVCaptureSession
和 AVCaptureDeviceInput
。一切正常,除非我尝试在 iPad 上旋转设备。 CameraPreview
未正确旋转并使用上一次旋转的输入。 (下图)我可以在 SwiftUI (based on this article) 中检查正在旋转的设备,但我不知道如何重新配置 CameraPreview
和 AVCaptureVideoPreviewLayer
的旋转。知道如何在我发现设备旋转后在 UIKit
中触发布局更新吗?
代码如下:
struct CameraView: View {
@StateObject var camera = CameraModel()
var body: some View {
CameraPreview(camera: camera)
.ignoresSafeArea(.all, edges: .all)
}
}
struct CameraPreview: UIViewRepresentable {
@ObservedObject var camera: CameraModel
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: UIScreen.main.bounds)
camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame = view.frame
//your own properies
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
//starting session
camera.session.startRunning()
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) { }
}
class CameraModel: NSObject, ObservableObject, AVCapturePhotoCaptureDelegate {
@Published var session = AVCaptureSession()
@Published var preview: AVCaptureVideoPreviewLayer!
@Published var output = AVCapturePhotoOutput()
func setUp() {
do {
self.session.beginConfiguration()
let device = AVCaptureDevice.default(for: .video)
let input = try AVCaptureDeviceInput(device:device!)
if self.session.canAddInput(input) {
self.session.addInput(input)
}
if self.session.canAddOutput(self.output) {
self.session.addOutput(self.output)
}
self.session.commitConfiguration()
}catch {
print(error.localizedDescription)
}
}
}
我通过以下方式解决了这个问题:
将预览帧调整为 bounds
而不是 frame
。
当我在某些超级视图 View
上检测到设备方向发生变化时,我更改了 deviceRotation
变量的值,这会自动触发 updateUIView
函数。
struct CameraPreview: UIViewRepresentable {
@ObservedObject var camera: CameraModel
var deviceRotation: UIDeviceOrientation
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: UIScreen.main.bounds)
camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame = view.bounds
//your own properies
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
//starting session
camera.session.startRunning()
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) {
let view = UIView(frame: UIScreen.main.bounds)
camera.preview.frame = view.bounds
}
}
在 AVCaptureConnection
上手动设置 AVCaptureVideoOrientation
以更正设备方向。每次检测到方向变化时,我都会这样做:
previewConnection.videoPreviewLayer?.connection?.videoOrientation = orientation.videoOrientation
我正在使用 CameraPreview
(UIViewRepresentable
) 作为 UIKit
和 SwiftUI
之间的桥梁。 CameraPreview
配置为CameraModel
,使用AVCaptureVideoPreviewLayer
。 CameraModel
正在配置 AVCaptureSession
和 AVCaptureDeviceInput
。一切正常,除非我尝试在 iPad 上旋转设备。 CameraPreview
未正确旋转并使用上一次旋转的输入。 (下图)我可以在 SwiftUI (based on this article) 中检查正在旋转的设备,但我不知道如何重新配置 CameraPreview
和 AVCaptureVideoPreviewLayer
的旋转。知道如何在我发现设备旋转后在 UIKit
中触发布局更新吗?
代码如下:
struct CameraView: View {
@StateObject var camera = CameraModel()
var body: some View {
CameraPreview(camera: camera)
.ignoresSafeArea(.all, edges: .all)
}
}
struct CameraPreview: UIViewRepresentable {
@ObservedObject var camera: CameraModel
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: UIScreen.main.bounds)
camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame = view.frame
//your own properies
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
//starting session
camera.session.startRunning()
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) { }
}
class CameraModel: NSObject, ObservableObject, AVCapturePhotoCaptureDelegate {
@Published var session = AVCaptureSession()
@Published var preview: AVCaptureVideoPreviewLayer!
@Published var output = AVCapturePhotoOutput()
func setUp() {
do {
self.session.beginConfiguration()
let device = AVCaptureDevice.default(for: .video)
let input = try AVCaptureDeviceInput(device:device!)
if self.session.canAddInput(input) {
self.session.addInput(input)
}
if self.session.canAddOutput(self.output) {
self.session.addOutput(self.output)
}
self.session.commitConfiguration()
}catch {
print(error.localizedDescription)
}
}
}
我通过以下方式解决了这个问题:
将预览帧调整为
bounds
而不是frame
。当我在某些超级视图
View
上检测到设备方向发生变化时,我更改了deviceRotation
变量的值,这会自动触发updateUIView
函数。struct CameraPreview: UIViewRepresentable { @ObservedObject var camera: CameraModel var deviceRotation: UIDeviceOrientation func makeUIView(context: Context) -> UIView { let view = UIView(frame: UIScreen.main.bounds) camera.preview = AVCaptureVideoPreviewLayer(session: camera.session) camera.preview.frame = view.bounds //your own properies camera.preview.videoGravity = .resizeAspectFill view.layer.addSublayer(camera.preview) //starting session camera.session.startRunning() return view } func updateUIView(_ uiView: UIViewType, context: Context) { let view = UIView(frame: UIScreen.main.bounds) camera.preview.frame = view.bounds } }
在
AVCaptureConnection
上手动设置AVCaptureVideoOrientation
以更正设备方向。每次检测到方向变化时,我都会这样做:previewConnection.videoPreviewLayer?.connection?.videoOrientation = orientation.videoOrientation