在 iOS 掃碼組件中實現自動對焦和曝光,核心依賴AVFoundation框架的AVCaptureDevice類,通過配置設備的對焦模式、曝光模式,結合用户交互(如點擊對焦)或環境檢測(如弱光自動補光)來實現智能調控。以下是分步實現方案,包含基礎自動對焦 / 曝光、手動觸發優化及特殊場景適配: 一、基礎配置:開啓自動對焦與曝光 首先需初始化AVCaptureSession並獲取攝像頭設備(通常為後置攝像頭),然後配置對焦和曝光的默認模式: swift import AVFoundation import UIKit
class ScanViewController: UIViewController { private let captureSession = AVCaptureSession() private var captureDevice: AVCaptureDevice? private let previewLayer = AVCaptureVideoPreviewLayer()
override func viewDidLoad() {
super.viewDidLoad()
setupCaptureSession()
}
// 初始化採集會話
private func setupCaptureSession() {
// 1. 獲取後置攝像頭設備
guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
print("獲取攝像頭設備失敗")
return
}
captureDevice = device
// 2. 配置輸入(攝像頭)
guard let input = try? AVCaptureDeviceInput(device: device) else {
print("配置攝像頭輸入失敗")
return
}
if captureSession.canAddInput(input) {
captureSession.addInput(input)
}
// 3. 配置輸出(元數據,用於識別條碼)
let metadataOutput = AVCaptureMetadataOutput()
if captureSession.canAddOutput(metadataOutput) {
captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [.qr, .code128] // 指定識別碼制
}
// 4. 配置預覽層
previewLayer.session = captureSession
previewLayer.frame = view.bounds
previewLayer.videoGravity = .resizeAspectFill
view.layer.insertSublayer(previewLayer, at: 0)
// 5. 開啓自動對焦和曝光
setupAutoFocusAndExposure()
// 啓動採集會話
captureSession.startRunning()
}
// 配置自動對焦與曝光
private func setupAutoFocusAndExposure() {
guard let device = captureDevice else { return }
do {
try device.lockForConfiguration() // 鎖定配置(必須)
// 自動對焦:持續自動對焦(適合掃碼時隨條碼移動調整)
if device.isFocusModeSupported(.continuousAutoFocus) {
device.focusMode = .continuousAutoFocus
device.focusPointOfInterest = CGPoint(x: 0.5, y: 0.5) // 對焦中心區域
}
// 自動曝光:持續自動曝光(根據環境光線調整)
if device.isExposureModeSupported(.continuousAutoExposure) {
device.exposureMode = .continuousAutoExposure
device.exposurePointOfInterest = CGPoint(x: 0.5, y: 0.5) // 曝光中心區域
}
device.unlockForConfiguration() // 解鎖配置
} catch {
print("配置對焦/曝光失敗:\(error)")
}
}
}
// 實現元數據代理(掃碼識別邏輯) extension ScanViewController: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { // 處理識別結果... } } 二、進階優化:點擊屏幕手動對焦 + 曝光 掃碼時用户可能需要對準特定區域(如遠距離條碼),添加點擊預覽層觸發對焦 / 曝光: swift // 在viewDidLoad中添加點擊手勢 override func viewDidLoad() { super.viewDidLoad() setupCaptureSession() let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) view.addGestureRecognizer(tapGesture) }
// 處理點擊對焦 @objc private func handleTap(_ gesture: UITapGestureRecognizer) { let point = gesture.location(in: view) // 將點擊座標轉換為攝像頭的興趣區域座標(攝像頭座標系:0~1,原點在左上角) let cameraPoint = previewLayer.captureDevicePointConverted(fromLayerPoint: point) focus(with: cameraPoint) }
// 手動對焦+曝光 private func focus(with point: CGPoint) { guard let device = captureDevice else { return } do { try device.lockForConfiguration()
// 1. 手動對焦到點擊位置
if device.isFocusModeSupported(.autoFocus) {
device.focusPointOfInterest = point
device.focusMode = .autoFocus // 單次自動對焦(對焦後恢復持續自動對焦)
// 對焦完成後恢復持續對焦(可選)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if device.isFocusModeSupported(.continuousAutoFocus) {
device.focusMode = .continuousAutoFocus
}
}
}
// 2. 手動曝光到點擊位置
if device.isExposureModeSupported(.autoExpose) {
device.exposurePointOfInterest = point
device.exposureMode = .autoExpose // 單次自動曝光
// 曝光完成後恢復持續曝光(可選)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if device.isExposureModeSupported(.continuousAutoExposure) {
device.exposureMode = .continuousAutoExposure
}
}
}
device.unlockForConfiguration()
} catch {
print("手動對焦/曝光失敗:\(error)")
}
} 三、弱光場景:自定義曝光參數(ISO / 快門) 若環境光線過暗,可手動調整曝光參數(如提高 ISO、延長快門時間),實現弱光補光: swift // 弱光下增強曝光 private func enhanceLowLightExposure() { guard let device = captureDevice else { return } do { try device.lockForConfiguration()
// 檢查是否支持自定義曝光
if device.isExposureModeSupported(.custom) {
// 設置曝光時長(單位:秒,需在device.minExposureDuration和maxExposureDuration之間)
let exposureDuration = CMTimeMakeWithSeconds(1/30, preferredTimescale: 1000000000) // 30fps
// 設置ISO(需在device.minISO和maxISO之間)
let iso = min(400, device.maxISO) // 提高ISO至400(避免噪點過多)
device.setExposureModeCustom(duration: exposureDuration, iso: iso, completionHandler: nil)
}
device.unlockForConfiguration()
} catch {
print("自定義曝光失敗:\(error)")
}
} 四、閃光燈聯動:弱光自動開啓閃光燈 結合環境光檢測,在弱光時自動打開閃光燈輔助照明: swift // 自動控制閃光燈 private func autoToggleTorch() { guard let device = captureDevice, device.hasTorch else { return } do { try device.lockForConfiguration()
// 模擬環境光檢測(實際可通過亮度傳感器獲取)
let isLowLight = true // 弱光標記
device.torchMode = isLowLight ? .on : .off
// 設置閃光燈亮度(0~1)
if device.isTorchModeSupported(.on) {
try device.setTorchModeOn(level: 0.8)
}
device.unlockForConfiguration()
} catch {
print("閃光燈控制失敗:\(error)")
}
} 五、關鍵注意事項 配置鎖定機制:所有對AVCaptureDevice的配置修改必須在lockForConfiguration()和unlockForConfiguration()之間進行,否則會崩潰。 設備能力檢查:不同設備支持的對焦 / 曝光模式不同(如部分舊機型不支持自定義曝光),需通過isFocusModeSupported()、isExposureModeSupported()判斷。 座標系轉換:點擊屏幕的座標是UIKit座標系(原點在左上角),需通過previewLayer.captureDevicePointConverted(fromLayerPoint:)轉換為攝像頭的興趣區域座標(0~1 範圍)。 性能平衡:持續自動對焦 / 曝光會增加 CPU 消耗,若需極致性能,可在識別到條碼後暫停自動調整。 總結 通過AVFoundation的AVCaptureDevice配置,可實現基礎自動對焦 / 曝光、點擊手動調控及弱光場景優化,結合閃光燈聯動能進一步提升掃碼成功率。實際開發中需根據業務場景(如支付掃碼、商品盤點)調整策略,例如支付場景優先保證識別速度,商品盤點場景支持連續對焦適配批量掃碼。