You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS/Swift实现自动对焦后自动拍照的方法

iOS自动对焦并自动拍照入门指南

嘿,作为iOS开发新手,这个自动对焦+自动拍照的需求其实没你想的那么复杂,核心是用AVFoundation框架来搞定——这是iOS原生处理相机、音频等媒体的底层框架,也是实现这类功能的标准方案。我给你拆解成几个关键步骤,再附上可运行的简化代码,帮你快速上手~

1. 先搞定相机权限(必做!)

iOS对隐私权限管控很严,访问相机必须提前申请权限:

  • 打开项目的Info.plist,添加NSCameraUsageDescription键,值填一句用户能看懂的说明,比如"需要访问相机来自动拍摄照片"
  • 代码里要主动请求权限,只有用户同意后才能继续配置相机:
    AVCaptureDevice.requestAccess(for: .video) { granted in
        guard granted else {
            // 这里可以弹提示告诉用户去设置里开启权限
            return
        }
        // 权限通过,主线程配置相机
        DispatchQueue.main.async {
            self.setupCameraSession()
        }
    }
    

2. 配置相机核心会话

相机功能的核心是AVCaptureSession,它负责协调输入(摄像头)和输出(照片/视频):

  • 初始化会话并设置预设:captureSession.sessionPreset = .photo(适合拍照场景)。
  • 获取后置摄像头:用AVCaptureDevice.DiscoverySession筛选出后置的广角相机。
  • 创建输入输出对象:把摄像头作为输入加入会话,把AVCapturePhotoOutput作为照片输出加入会话。
  • 添加预览层:让用户能看到相机画面,把AVCaptureVideoPreviewLayer加到你的视图上。

3. 实现自动对焦+监听对焦完成

这是实现自动拍照的关键——我们需要让相机自动对焦,并且在对焦完成的瞬间触发拍照:

  • 配置自动对焦:锁定摄像头配置,设置focusMode = .autoFocus,对焦点设为画面中心(CGPoint(x:0.5, y:0.5)),然后解锁配置。
  • 监听对焦状态:用NSKeyValueObservation监听摄像头的adjustingFocus属性,当这个属性从true变为false时,就说明对焦完成了。

4. 对焦完成自动触发拍照

监听到对焦完成的信号后,调用AVCapturePhotoOutputcapturePhoto(with:delegate:)方法即可自动拍照,同时要实现AVCapturePhotoCaptureDelegate协议来处理拍摄完成的照片。

完整简化代码示例

下面是一个ViewController的核心代码,你可以直接放到项目里测试(记得用真机!模拟器没有相机功能):

import UIKit
import AVFoundation

class AutoCaptureCameraVC: UIViewController, AVCapturePhotoCaptureDelegate {
    private let captureSession = AVCaptureSession()
    private var photoOutput = AVCapturePhotoOutput()
    private var focusObservation: NSKeyValueObservation?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        requestCameraPermission()
    }

    private func requestCameraPermission() {
        AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
            guard granted else {
                DispatchQueue.main.async {
                    let alert = UIAlertController(title: "权限提示", message: "请在设置中开启相机权限", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "知道了", style: .default))
                    self?.present(alert, animated: true)
                }
                return
            }
            DispatchQueue.main.async {
                self?.setupCamera()
            }
        }
    }

    private func setupCamera() {
        captureSession.sessionPreset = .photo

        // 获取后置摄像头
        guard let cameraDevice = AVCaptureDevice.DiscoverySession(
            deviceTypes: [.builtInWideAngleCamera],
            mediaType: .video,
            position: .back
        ).devices.first else {
            print("找不到后置摄像头")
            return
        }

        do {
            // 添加相机输入
            let cameraInput = try AVCaptureDeviceInput(device: cameraDevice)
            if captureSession.canAddInput(cameraInput) {
                captureSession.addInput(cameraInput)
            }

            // 添加照片输出
            if captureSession.canAddOutput(photoOutput) {
                captureSession.addOutput(photoOutput)
            }

            // 添加预览层
            let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            previewLayer.frame = view.bounds
            previewLayer.videoGravity = .resizeAspectFill
            view.layer.addSublayer(previewLayer)

            // 配置自动对焦
            try cameraDevice.lockForConfiguration()
            cameraDevice.focusMode = .autoFocus
            cameraDevice.focusPointOfInterest = CGPoint(x: 0.5, y: 0.5)
            cameraDevice.unlockForConfiguration()

            // 监听对焦完成
            focusObservation = cameraDevice.observe(\.adjustingFocus) { [weak self] device, _ in
                guard !device.adjustingFocus else { return }
                // 对焦完成,触发拍照
                self?.takeAutoPhoto()
                // 如果只需要拍一次,就移除监听避免重复触发
                self?.focusObservation?.invalidate()
            }

            // 启动相机会话
            captureSession.startRunning()
        } catch {
            print("相机配置出错:\(error.localizedDescription)")
        }
    }

    private func takeAutoPhoto() {
        let photoSettings = AVCapturePhotoSettings()
        // 设置预览格式(可选,用于实时预览)
        if let previewFormat = photoSettings.availablePreviewPhotoPixelFormatTypes.first {
            photoSettings.previewPhotoFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewFormat]
        }
        photoOutput.capturePhoto(with: photoSettings, delegate: self)
    }

    // 处理拍摄完成的照片
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        guard let imageData = photo.fileDataRepresentation(), let capturedImage = UIImage(data: imageData) else {
            print("照片处理失败:\(error?.localizedDescription ?? "未知错误")")
            return
        }

        // 这里可以把照片保存到相册,或者展示在界面上
        let imageView = UIImageView(image: capturedImage)
        imageView.frame = view.bounds
        imageView.contentMode = .scaleAspectFit
        view.addSubview(imageView)

        // 停止相机会话(可选,根据需求决定是否继续使用相机)
        captureSession.stopRunning()
    }
}

几个关键注意点

  • 必须用真机测试:模拟器没有硬件相机,无法运行相机相关代码。
  • 权限一定要加:如果Info.plist里没加NSCameraUsageDescription,App会直接崩溃。
  • 线程安全:相机会话的配置和启动要在主线程或者专门的串行队列里处理,避免线程冲突。
  • 重复拍摄的调整:如果需要重复自动对焦拍照,不要调用focusObservation?.invalidate(),但要注意添加防抖逻辑,避免频繁触发拍照。

内容的提问来源于stack exchange,提问作者Kévin Esprit

火山引擎 最新活动