iOS18适配:Swift用UIGraphicsImageRenderer实现UIImage圆形缩放裁剪
iOS 18适配:用UIGraphicsImageRenderer重构圆形图片缩放裁剪功能
iOS 18 开始UIGraphicsBeginImageContextWithOptions、UIGraphicsGetCurrentContext、UIGraphicsEndImageContext这三个API被标记为废弃,原有基于这些API实现的图片圆形缩放裁剪代码会崩溃,需要改用UIGraphicsImageRenderer完成相同功能。
原有废弃API实现代码
func scaleCropAndCircleImage(image:UIImage, frame:CGRect) throws -> UIImage { enum FunctionError: Error { case nilContext case nilImage } UIGraphicsBeginImageContextWithOptions(CGSizeMake(frame.size.width, frame.size.height), false, 0.0) guard let context = UIGraphicsGetCurrentContext() else { throw FunctionError.nilContext } // width and heights of passed values of uiimage and CGRect let passedimageWidth = image.size.width let passedimageHeight = image.size.height let passedrectWidth = frame.size.width let passedrectHeight = frame.size.height // scale factor calculation let scaleFactorX = passedrectWidth/passedimageWidth let scaleFactorY = passedrectHeight/passedimageHeight // centre of the circle calculation let imageCentreX = passedrectWidth/2 let imageCentreY = passedrectHeight/2 // Creating and clipping to a CIRCULAR Path let radius = passedrectWidth/2 context.beginPath() context.addArc(center: CGPoint(x: imageCentreX, y: imageCentreY), radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: false) context.closePath() context.clip() //Seting the scaling factor for graphics context context.scaleBy(x: scaleFactorX, y: scaleFactorY) let myRect:CGRect = CGRectMake(0, 0, passedimageWidth, passedimageHeight) image.draw(in: myRect) let newCroppedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() guard let newCroppedImage else { throw FunctionError.nilImage } return newCroppedImage }
未完成的改写尝试
import UIKit extension UIImage { func roundedCornerImage(with radius: CGFloat) -> UIImage { let format = UIGraphicsImageRendererFormat() format.scale = scale let renderer = UIGraphicsImageRenderer(size: size, format: format) return renderer.image { rendererContext in let rect = CGRect(origin: .zero, size: size) let path = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: radius, height: radius)) path.close() let cgContext = rendererContext.cgContext cgContext.saveGState() path.addClip() draw(in: rect) cgContext.restoreGState() } } }
完整重构实现
func scaleCropAndCircleImage(image: UIImage, frame: CGRect) throws -> UIImage { enum FunctionError: Error { case nilImage } let targetSize = frame.size let format = UIGraphicsImageRendererFormat() // 对应原代码中0.0的scale参数,使用当前屏幕缩放比例 format.scale = 0.0 let renderer = UIGraphicsImageRenderer(size: targetSize, format: format) let resultImage = renderer.image { rendererContext in let cgContext = rendererContext.cgContext // 沿用原逻辑计算缩放因子 let imageWidth = image.size.width let imageHeight = image.size.height let scaleFactorX = targetSize.width / imageWidth let scaleFactorY = targetSize.height / imageHeight // 创建圆形裁剪路径,和原逻辑完全一致 let center = CGPoint(x: targetSize.width / 2, y: targetSize.height / 2) let radius = targetSize.width / 2 cgContext.beginPath() cgContext.addArc(center: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: false) cgContext.closePath() cgContext.clip() // 缩放上下文,匹配原逻辑 cgContext.scaleBy(x: scaleFactorX, y: scaleFactorY) // 绘制原图 let imageRect = CGRect(origin: .zero, size: image.size) image.draw(in: imageRect) } guard resultImage != nil else { throw FunctionError.nilImage } return resultImage }
重构关键点说明
- 用
UIGraphicsImageRenderer替代手动上下文管理,无需手动开启/关闭上下文 - 完全保留原有的缩放因子计算、圆形裁剪逻辑,确保最终效果和旧代码一致
- 移除了
nilContext错误分支:UIGraphicsImageRenderer会自动处理上下文创建,不会出现上下文为空的情况 format.scale = 0.0对应原API的第三个参数,保证生成图片的清晰度匹配屏幕
内容的提问来源于stack exchange,提问作者user37511008
相关产品推荐
相关产品推荐

