You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在iPad的UIImagePickerController相机运行时添加圆形裁剪器?

实现iPad相机的圆形裁剪功能

我帮你整理了完整的实现方案,基于你提供的imagePickerHelper类,添加圆形裁剪器并实现拍摄后的自动裁剪:

第一步:修改工具类,添加裁剪相关逻辑

我们先扩展这个类,实现UIImagePickerControllerDelegate和UINavigationControllerDelegate,同时加入自定义的圆形遮罩视图,以及拍摄后的裁剪逻辑:

import UIKit

class ImagePickerHelper: NSObject {
    var chosenImage: UIImage?
    var getImage: ((_ selectedItem: UIImage, _ selectedValue: Bool) -> Void)?
    static let shared = ImagePickerHelper()
    
    // 存储屏幕上圆形裁剪区域的frame,用于后续图片映射裁剪
    private var cropCircleFrame: CGRect = .zero
    
    func openCamera(withParentViewController parentVC: UIViewController) {
        guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
            getImage?(UIImage(), false)
            return
        }
        
        let picker = UIImagePickerController()
        picker.sourceType = .camera
        picker.delegate = self
        picker.allowsEditing = false // 关闭系统默认编辑,我们自定义处理
        
        // 给相机添加圆形裁剪遮罩
        let overlayView = createCropOverlay(frame: picker.view.bounds)
        picker.cameraOverlayView = overlayView
        
        parentVC.present(picker, animated: true)
    }
    
    // 创建带圆形透明区域的遮罩视图
    private func createCropOverlay(frame: CGRect) -> UIView {
        let overlay = UIView(frame: frame)
        overlay.backgroundColor = UIColor.black.withAlphaComponent(0.7)
        
        // 计算圆形尺寸:取屏幕宽高中较小值的80%,保证圆形居中且不超出屏幕
        let circleSize = min(frame.width, frame.height) * 0.8
        let circleOriginX = (frame.width - circleSize) / 2
        let circleOriginY = (frame.height - circleSize) / 2
        cropCircleFrame = CGRect(x: circleOriginX, y: circleOriginY, width: circleSize, height: circleSize)
        
        // 绘制遮罩路径:全屏填充,减去圆形区域
        let maskLayer = CAShapeLayer()
        let fullPath = UIBezierPath(rect: overlay.bounds)
        let circlePath = UIBezierPath(ovalIn: cropCircleFrame).reversing()
        fullPath.append(circlePath)
        maskLayer.path = fullPath.cgPath
        overlay.layer.mask = maskLayer
        
        // 添加白色圆形边框,增强视觉引导
        let borderLayer = CAShapeLayer()
        borderLayer.path = UIBezierPath(ovalIn: cropCircleFrame).cgPath
        borderLayer.strokeColor = UIColor.white.cgColor
        borderLayer.lineWidth = 2
        borderLayer.fillColor = UIColor.clear.cgColor
        overlay.layer.addSublayer(borderLayer)
        
        return overlay
    }
    
    // 将拍摄原图裁剪为圆形区域的图片
    private func cropImageToCircle(originalImage: UIImage) -> UIImage {
        // 计算相机预览与实际图片的比例:相机输出图片分辨率远高于屏幕,需要做坐标映射
        let imageSize = originalImage.size
        let previewSize = UIScreen.main.bounds.size
        let scaleX = imageSize.width / previewSize.width
        let scaleY = imageSize.height / previewSize.height
        
        // 把屏幕上的圆形区域转换为图片坐标系的裁剪区域
        let scaledCropFrame = CGRect(
            x: cropCircleFrame.origin.x * scaleX,
            y: cropCircleFrame.origin.y * scaleY,
            width: cropCircleFrame.size.width * scaleX,
            height: cropCircleFrame.size.height * scaleY
        )
        
        // 执行裁剪
        guard let croppedCGImage = originalImage.cgImage?.cropping(to: scaledCropFrame) else {
            return originalImage
        }
        
        // 可选:将裁剪后的矩形图片转为带透明背景的圆形图片
        let croppedImage = UIImage(cgImage: croppedCGImage)
        let imageView = UIImageView(image: croppedImage)
        imageView.layer.cornerRadius = croppedImage.size.width / 2
        imageView.clipsToBounds = true
        
        // 渲染圆形图片
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, UIScreen.main.scale)
        imageView.layer.render(in: UIGraphicsGetCurrentContext()!)
        let finalCircularImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        
        return finalCircularImage
    }
}

// 实现UIImagePickerController代理方法
extension ImagePickerHelper: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true)
        
        guard let originalImage = info[.originalImage] as? UIImage else {
            getImage?(UIImage(), false)
            return
        }
        
        // 裁剪图片并回调结果
        let croppedImage = cropImageToCircle(originalImage: originalImage)
        chosenImage = croppedImage
        getImage?(croppedImage, true)
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true)
        getImage?(UIImage(), false)
    }
}

第二步:在ViewController中调用

你可以在需要打开相机的地方这样使用:

class YourViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func openCameraButtonTapped(_ sender: UIButton) {
        ImagePickerHelper.shared.openCamera(withParentViewController: self)
        ImagePickerHelper.shared.getImage = { [weak self] image, success in
            guard success else { return }
            // 这里拿到裁剪后的圆形图片,做你需要的后续操作
            print("已获取裁剪后的圆形图片:\(image.size)")
        }
    }
}

关键细节说明

  • 遮罩视觉引导:半透明遮罩+白色边框,让用户清晰知道拍摄的有效区域
  • 比例适配:解决了相机预览分辨率与实际输出图片分辨率不一致的问题,保证裁剪区域精准
  • 可选的圆形图片:如果只需要裁剪出圆形区域的矩形图片,可以去掉最后的圆形渲染步骤,直接返回UIImage(cgImage: croppedCGImage)即可

内容的提问来源于stack exchange,提问作者Subhajit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:43:05