如何在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
相关产品推荐
相关产品推荐

