Swift自定义iPhone相机:最优相机选型、变焦及Tap to Focus实现
Swift自定义相机最佳实践与问题解答
适配所有iPhone机型的deviceTypes设置
要覆盖所有iPhone后置相机,deviceTypes应包含以下类型,同时将position设为.back(仅筛选后置相机):
let deviceTypes: [AVCaptureDevice.DeviceType] = [ .builtInTripleCamera, .builtInDualCamera, .builtInDualWideCamera, .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera ] let discoverySession = AVCaptureDevice.DiscoverySession( deviceTypes: deviceTypes, mediaType: .video, position: .back )
这套配置能自动适配从老款单广角机型到最新三摄、双摄机型,系统会返回当前设备可用的后置相机列表。
多合一相机VS手动切换相机
优先选择builtInTripleCamera、builtInDualCamera这类多合一相机设备:
- 这类设备是苹果系统整合的,自动处理不同镜头间的变焦切换、画质同步、过渡动画,体验和原生相机完全对齐。
- 手动切换单相机需要自行处理镜头间的参数同步(如对焦、曝光)、变焦平滑过渡,容易出现卡顿或画质断层,开发成本更高。
- 仅当设备无多合一相机时(比如老款单广角iPhone),才需要考虑手动切换单相机。
手动切换相机的最佳方案(仅无多合一相机时使用)
- 枚举并分组可用相机:先获取所有可用后置相机,按它们的变焦范围(
minAvailableVideoZoomFactor和maxAvailableVideoZoomFactor)分组,比如超广角(0.5x)、广角(1x)、长焦(2x/3x)。 - 监听变焦变化:实时监听用户的变焦操作(如滑块拖动),当当前变焦系数超出当前相机的最大变焦范围时,切换到对应变焦区间的相机。
- 平滑切换会话:切换相机时,先暂停会话预览,替换
AVCaptureDeviceInput后再重启会话,同时保留当前对焦、曝光参数,避免画面突兀变化。 - 处理变焦系数映射:切换相机后,将当前变焦系数转换为新相机的对应值(比如从广角切换到长焦,1x对应长焦的2x)。
TripleCamera下Tap to Focus失效的修复方案
你的代码存在两个核心问题:坐标未转换和支持性检查不完整,修复后的实现如下:
关键修复点
- 屏幕坐标转相机坐标系:屏幕Y轴方向和相机设备Y轴方向相反,需将点击点通过预览层转换为相机设备的归一化坐标(0~1范围)。
- 完善支持性检查:除对焦模式外,还要检查相机是否支持对焦兴趣点设置。
- 适配多合一相机的对焦逻辑:多合一相机建议使用
.continuousAutoFocus模式(和原生相机一致),确保对焦持续稳定。
修复后的代码
func setFocusOnTap(screenPoint: CGPoint, previewView: UIView) { guard let cameraDevice = self.deviceInput?.device else { return } guard let previewLayer = previewView.layer as? AVCaptureVideoPreviewLayer else { return } // 转换屏幕点击点为相机设备的归一化坐标 let cameraPoint = previewLayer.captureDevicePointConverted(fromLayerPoint: screenPoint) do { try cameraDevice.lockForConfiguration() // 对焦设置:检查兴趣点和模式支持 if cameraDevice.isFocusPointOfInterestSupported, cameraDevice.isFocusModeSupported(.continuousAutoFocus) { cameraDevice.focusPointOfInterest = cameraPoint cameraDevice.focusMode = .continuousAutoFocus } // 曝光设置:同样检查兴趣点和模式支持 if cameraDevice.isExposurePointOfInterestSupported, cameraDevice.isExposureModeSupported(.continuousAutoExposure) { cameraDevice.exposurePointOfInterest = cameraPoint cameraDevice.exposureMode = .continuousAutoExposure } cameraDevice.isSubjectAreaChangeMonitoringEnabled = true cameraDevice.unlockForConfiguration() } catch { print("Failed to configure focus: \(error)") } }
额外注意事项
- 确保调用该方法时在主线程:AVCaptureDevice的配置操作必须在主线程执行,否则可能出现异常。
- 预览层的
videoGravity设为.resizeAspectFill(和原生相机一致),避免坐标转换偏差。
整体最佳实践总结
- 优先选用多合一相机设备,减少手动管理成本,保证体验一致性。
- 动态检测可用相机,不要硬编码特定机型,确保适配所有iPhone。
- 所有相机配置操作必须在主线程执行。
- 涉及坐标转换时,务必使用
AVCaptureVideoPreviewLayer的转换方法,避免手动计算出错。
内容的提问来源于stack exchange,提问作者Jesper Samuelsson
相关产品推荐
相关产品推荐

