将视图内容生成模糊图像,并返回一个模糊覆盖图层

未命名.png
extension UIView{
    /// 将视图内容生成模糊图像,并返回一个模糊覆盖图层(UIImageView)
    /// - Parameters:
    ///   - blurRadius: 模糊半径,值越大越模糊(推荐 30~50)
    ///   - completion: 模糊图像生成后的回调,返回 UIImageView(模糊层)
    @objc func makeTextAppearAsBlackBlob(blurRadius: CGFloat = 10.0,
                                   completion: @escaping (_ blurredImage: UIImageView?) -> Void) {
        
        // 1. 在主线程中渲染视图内容为图片(必须主线程才能确保文字等内容完整绘制)
        DispatchQueue.main.async {[weak self] in
            guard let self = self else { return }
            // 创建图像渲染器,大小为视图尺寸
            let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
            
            // 渲染 view 当前内容为 UIImage(截图)
            let snapshot = renderer.image { _ in
                self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
            }
            
            // 2. 在后台线程处理图像模糊,避免阻塞 UI
            DispatchQueue.global(qos: .userInitiated).async {
                // 转换为 CIImage 用于滤镜处理
                guard let ciImage = CIImage(image: snapshot),
                      let blurFilter = CIFilter(name: "CIGaussianBlur") else {
                    DispatchQueue.main.async { completion(nil) }
                    return
                }
                
                // 设置滤镜输入图像和模糊半径
                blurFilter.setValue(ciImage, forKey: kCIInputImageKey)
                blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey)
                
                // 获取滤镜输出图像(模糊后的图)
                guard let outputImage = blurFilter.outputImage else {
                    DispatchQueue.main.async { completion(nil) }
                    return
                }
                
                // 修正输出图像区域,避免高斯模糊造成边缘裁剪(扩大区域)
                let cropRect = ciImage.extent.insetBy(dx: -blurRadius, dy: -blurRadius)
                
                // 使用 CIContext 将输出图像转为 CGImage
                let context = CIContext()
                guard let cgImage = context.createCGImage(outputImage, from: cropRect) else {
                    DispatchQueue.main.async { completion(nil) }
                    return
                }
                
                // 回到主线程返回模糊视图
                DispatchQueue.main.async {
                    // 转换为 UIImage 后创建 UIImageView(作为模糊覆盖层)
                    let blurredImage = UIImage(cgImage: cgImage)
                    let imageView = UIImageView(image: blurredImage)
                    imageView.frame = self.bounds
                    completion(imageView)
                }
            }
        }
    }
}

使用示例

textView.makeTextAppearAsBlackBlob { [weak self] blurredImage in
    guard let self = self else { return }
    guard let blurredImage else{ return }
    textView.addSubview(blurredImage)
}

Label的扩展

extension UILabel {
    
    /// 为 UILabel 添加模糊遮罩图像,返回模糊图层 UIImageView
    /// - Parameters:
    ///   - blurRadius: 模糊半径(数值越大越模糊),默认 10
    ///   - completion: 生成模糊图后的回调,返回 UIImageView(已设置好 frame)
    override func makeTextAppearAsBlackBlob(blurRadius: CGFloat = 10.0,
                                            completion: @escaping (UIImageView?) -> Void) {
        // 设置文本颜色为黑色,确保模糊后更像“黑团”
        self.textColor = .cBlack
        
        // 异步到主线程
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            
            // 使用 UIGraphicsImageRenderer 截图 UILabel 内容(包括文字)
            let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
            let image = renderer.image { _ in
                // drawText 是 UILabel 的绘图方法,可以准确绘制 label 的文字
                self.drawText(in: self.bounds)
            }
            
            // 模糊处理放在后台线程
            DispatchQueue.global(qos: .userInitiated).async {
                let context = CIContext(options: nil)
                
                // 转换为 CIImage 用于滤镜处理
                guard let ciImage = CIImage(image: image),
                      let blurFilter = CIFilter(name: "CIGaussianBlur") else {
                    DispatchQueue.main.async { completion(nil) }
                    return
                }
                
                // 设置输入图像和模糊半径
                blurFilter.setValue(ciImage, forKey: kCIInputImageKey)
                blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey)
                
                // 获取模糊输出图像
                guard let output = blurFilter.outputImage else {
                    DispatchQueue.main.async { completion(nil) }
                    return
                }
                
                // ⚠️ 默认输出图像可能被裁剪,需扩大模糊区域
                let cropRect = ciImage.extent.insetBy(dx: -blurRadius, dy: -blurRadius)
                
                // 生成 CGImage 图像
                guard let cgImage = context.createCGImage(output, from: cropRect) else {
                    DispatchQueue.main.async { completion(nil) }
                    return
                }
                
                // 返回主线程回调 UIImageView
                DispatchQueue.main.async {
                    let blurredImage = UIImage(cgImage: cgImage)
                    let imageView = UIImageView(image: blurredImage)
                    imageView.frame = self.bounds
                    completion(imageView)
                }
            }
        }
    }
}

使用示例

label.makeTextAppearAsBlackBlob(blurRadius: 10) { blurredImage in
    guard let blurredImage else {
        return
    }
    label.superview?.addSubview(blurredImage)
    label.isHidden = true
}

仅供参考

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容