如何高性能的给UIImageView加个圆角?

361 阅读2分钟

在 iOS 开发中,为 UIImageView 添加圆角时,若直接使用 layer.cornerRadius + masksToBounds 会导致离屏渲染(Offscreen Rendering),在列表等高频场景下可能引发性能问题。以下是高性能实现圆角的几种方案:


⚡️ 高性能方案推荐

方案 1:Core Graphics 预处理圆角(推荐)

通过 CPU 预处理图片,生成带圆角的位图,避免 GPU 离屏渲染。

swift

extension UIImage {
    func roundedImage(with radius: CGFloat, size: CGSize) -> UIImage? {
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
        defer { UIGraphicsEndImageContext() }
        
        let path = UIBezierPath(
            roundedRect: rect,
            cornerRadius: radius
        )
        path.addClip() // 裁剪路径
        
        self.draw(in: rect) // 绘制图片
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

// 使用示例(异步处理避免阻塞主线程)
DispatchQueue.global(qos: .userInitiated).async {
    let resizedImage = originalImage.roundedImage(with: 10, size: imageView.bounds.size)
    DispatchQueue.main.async {
        imageView.image = resizedImage
    }
}

优点:彻底避免离屏渲染,适合静态图片。
注意:需在后台线程处理大图,主线程更新 UI。


方案 2:贝塞尔路径 + 遮罩层

通过 CAShapeLayer 添加圆角路径遮罩,但需注意图层混合(Blending)问题。

swift

let imageView = UIImageView()
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(
    roundedRect: imageView.bounds,
    cornerRadius: 10
).cgPath
imageView.layer.mask = maskLayer

优点:动态调整圆角。
缺点:若视图频繁变化(如动画),仍需性能优化。


方案 3:优化 cornerRadius 使用

若必须用 cornerRadius,确保 UIImageView 尺寸与图片尺寸一致,减少像素混合。

swift

imageView.layer.cornerRadius = 10
imageView.layer.masksToBounds = true
imageView.backgroundColor = .clear // 避免不必要的颜色混合

优化点

  1. 提前将图片缩放至 UIImageView 的尺寸。
  2. 避免在滚动视图中频繁调整圆角。

📊 性能对比

方法离屏渲染CPU 消耗GPU 消耗适用场景
Core Graphics 预处理静态图片
贝塞尔路径遮罩动态调整圆角
cornerRadius简单场景优化后使用

📌 关键优化原则

  1. 避免离屏渲染:离屏渲染会强制 GPU 中断当前流水线,显著降低帧率。
  2. 异步处理大图:使用 GCD 在后台线程处理图片裁剪。
  3. 缓存结果:对处理后的圆角图片进行缓存(如 NSCache)。
  4. 减少混合图层:确保 UIImageView 背景透明或不与圆角区域重叠。

总结

  • 静态图片:优先使用 Core Graphics 预处理,性能最佳。
  • 动态需求:可尝试 CAShapeLayer 方案,但需测试性能。
  • 简单场景:优化后的 cornerRadius 仍可接受,但需确保图片尺寸匹配。