Swift中AVFoundation自定义相机启动先放大后恢复正常问题排查
问题分析与解决方案
你遇到的相机启动时先放大再恢复正常的问题,核心原因是预览层与相机会话不同步,加上会话初始化时机的问题导致视觉跳变,以下是具体排查和修复步骤:
1. 预览层初始化过早
你在CameraViewModel的init方法中就创建了preview层,但此时相机会话(session)还未经过setUp()配置,预览层一开始绑定的是一个空会话。当后续setUp()完成会话配置并启动后,预览层才会重新适配真实的相机输入,这就导致了视觉上的缩放跳变。
修复:延迟预览层初始化
修改CameraViewModel的初始化逻辑,等待会话配置完成后再创建预览层:
override init() { super.init() self.checkPermission() // 移除原有的preview初始化代码,挪到setUp完成后 } func setUp(){ do { self.session.beginConfiguration() let cameraDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) // 强制锁定相机缩放为1.0,排除设备默认缩放异常 try cameraDevice!.lockForConfiguration() cameraDevice!.videoZoomFactor = 1.0 cameraDevice!.unlockForConfiguration() let videoInput = try AVCaptureDeviceInput(device: cameraDevice!) let audioDevice = AVCaptureDevice.default(for: .audio) let audioInput = try AVCaptureDeviceInput(device: audioDevice!) if self.session.canAddInput(videoInput) && self.session.canAddInput(audioInput){ self.session.addInput(videoInput) self.session.addInput(audioInput) } if self.session.canAddOutput(self.output){ self.session.addOutput(self.output) } if self.session.canAddOutput(self.photoOutput) { self.session.addOutput(self.photoOutput) } self.session.commitConfiguration() // 会话配置完成后,在主线程初始化预览层 DispatchQueue.main.async { self.preview = AVCaptureVideoPreviewLayer(session: self.session) self.preview.videoGravity = .resizeAspectFill } // 配置完成后启动会话,避免提前启动导致的异常 DispatchQueue.global(qos: .userInitiated).async { if !self.session.isRunning { self.session.startRunning() } } } catch { print(error.localizedDescription) } }
2. 预览层未响应会话更新
原CameraPreview的updateUIView方法是空的,当preview层更新时,UIView无法同步刷新,导致旧的预览层残留或适配错误。
修复:在updateUIView中同步预览层
修改CameraPreview的updateUIView方法,确保预览层随cameraModel.preview的变化而更新:
func updateUIView(_ uiView: UIView, context: Context) { guard let preview = cameraModel.preview else { return } // 移除旧的预览层,避免叠加 uiView.layer.sublayers?.filter { $0 is AVCaptureVideoPreviewLayer }.forEach { $0.removeFromSuperlayer() } preview.frame = uiView.bounds preview.videoGravity = .resizeAspectFill uiView.layer.addSublayer(preview) }
3. 会话启动时机优化
原代码在CameraPreview的makeUIView中启动会话,此时会话可能还未完成配置。将会话启动逻辑挪到setUp方法的末尾,确保配置完成后再启动,避免会话状态不稳定导致的预览异常。
完成以上修改后,相机启动时就会直接加载正确的预览画面,不会出现先放大再恢复的跳变问题。
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

