如何在UIKit实现SwiftUI式向外模糊?解决CIGaussianBlur内缩问题
在UIKit中实现SwiftUI风格的向外模糊效果
使用CIGaussianBlur处理图片时,UIImageView会呈现从边框向内模糊、图像收缩的效果;而SwiftUI中调用.blur()方法是从边框向外模糊的表现。如果想在UIKit里复刻后者的效果,直接使用CIAffineClamp会让模糊在边框处停止,无法满足需求。
解决方案思路
要实现向外模糊,核心是先给原图片添加与模糊半径相等的扩展边距,将图片边缘像素向外延展(匹配SwiftUI模糊的边缘处理逻辑),再应用高斯模糊,最后裁剪回原图片尺寸。这样模糊效果会向外扩散,而非向内收缩。
完整代码实现
private let context = CIContext() private let blurFilter = CIFilter(name: "CIGaussianBlur")! private let clampFilter = CIFilter(name: "CIAffineClamp")! private func createOutwardBlurredImage(using image: UIImage, blurRadius: CGFloat) -> UIImage? { guard let inputImage = CIImage(image: image) else { return nil } // 根据模糊半径扩展图像范围,为向外模糊预留空间 let extendDistance = blurRadius let extendedExtent = inputImage.extent.insetBy(dx: -extendDistance, dy: -extendDistance) // 用CIAffineClamp延展图像边缘像素,避免模糊时边缘出现收缩或透明 clampFilter.setValue(inputImage, forKey: kCIInputImageKey) clampFilter.setValue(CGAffineTransform.identity, forKey: kCIInputTransformKey) guard let clampedImage = clampFilter.outputImage?.cropped(to: extendedExtent) else { return nil } // 应用高斯模糊 blurFilter.setValue(clampedImage, forKey: kCIInputImageKey) blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey) guard let blurredImage = blurFilter.outputImage else { return nil } // 裁剪回原图像尺寸,得到向外模糊的最终效果 guard let cgImage = context.createCGImage(blurredImage, from: inputImage.extent) else { return nil } return UIImage(cgImage: cgImage) }
代码关键点说明
- 扩展图像范围:通过
insetBy传入负数,将图像的上下左右边界向外扩展,扩展距离等于模糊半径,确保模糊效果有足够空间向外扩散。 - 边缘像素延展:
CIAffineClamp会把图像边缘的像素向外复制填充,这样在模糊时,边缘区域不会因为没有像素来源而出现收缩或变黑。 - 裁剪回原尺寸:模糊完成后裁剪回原图像的extent,保证最终输出的图片大小和原图一致,但带有向外扩散的模糊效果。
内容的提问来源于stack exchange,提问作者Richard Witherspoon
相关产品推荐
相关产品推荐

