最近在重构浪浪山App的UI,设计师希望能够实现一种类似毛玻璃但更加通透、更具质感的视觉效果,类似于给APP裹上 Liquid Glass “琉璃罩”。传统的UIVisualEffectView虽然可以实现毛玻璃效果,但可定制性较差,无法满足设计师对颜色、模糊半径、透明度等细节的精细控制。因此,我们需要寻找一种更加灵活、可控的方案。
Liquid Glass效果的底层原理:深入了解 Core Image Filters
Liquid Glass 效果本质上是一种复杂的图像处理过程,它主要依赖于 Core Image Filters 实现。Core Image 是苹果提供的一套强大的图像处理框架,内置了大量的图像滤镜,可以对图像进行各种变换和处理。实现 Liquid Glass 效果,我们需要组合使用多个滤镜,主要包括以下几个步骤:
高斯模糊 (Gaussian Blur): 使用
CIGaussianBlur滤镜对背景图像进行模糊处理,这是实现毛玻璃效果的基础。色彩叠层 (Color Overlay): 使用
CIColorOverlay滤镜在模糊后的图像上叠加一层颜色,以改变整体的色调和饱和度。这个操作可以模拟光线穿过“琉璃”的效果。
噪点添加 (Noise Reduction): 为了增加视觉上的真实感,可以适当地添加一些噪点。可以使用
CIRandomGenerator滤镜生成随机噪点,然后使用CIOverlayBlendMode滤镜将其叠加到图像上。透明度调整 (Alpha Adjustment): 通过调整图层的透明度,可以控制 Liquid Glass 效果的强度。
CIContext 的重要性:CPU vs GPU渲染
值得注意的是,Core Image 的滤镜操作最终需要在 CIContext 中进行渲染。CIContext 可以选择使用 CPU 或 GPU 进行渲染。通常情况下,GPU 渲染的效率更高,但对于一些复杂的滤镜组合,CPU 渲染可能会更加稳定。在实际应用中,我们需要根据设备的性能和滤镜的复杂度来选择合适的渲染方式。我们可以通过以下代码来创建 CIContext:
// 使用 GPU 渲染
let context = CIContext()
// 使用 CPU 渲染
let context = CIContext(options: [.useSoftwareRenderer : true])
iOS代码实现:打造Liquid Glass“琉璃罩”组件
下面是一个简单的示例代码,演示如何使用 Core Image Filters 实现 Liquid Glass 效果:
import UIKit
import CoreImage.CIFilterBuiltins
class LiquidGlassView: UIView {
private let imageView = UIImageView()
private let blurRadius: CGFloat = 20 // 模糊半径
private let overlayColor: UIColor = UIColor(red: 0.2, green: 0.4, blue: 0.6, alpha: 0.3) // 叠加颜色
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
private func setupView() {
// 添加背景图片
imageView.frame = bounds
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
addSubview(imageView)
// 创建 CIContext
let context = CIContext()
// 创建 CIImage
guard let inputImage = CIImage(image: UIImage(named: "background_image")!) else { return }
// 1. 高斯模糊
let blurFilter = CIFilter.gaussianBlur()
blurFilter.setValue(inputImage, forKey: kCIInputImageKey)
blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey)
// 2. 色彩叠层
let overlayFilter = CIFilter.colorOverlay()
overlayFilter.setValue(blurFilter.outputImage!, forKey: kCIInputImageKey)
overlayFilter.setValue(CIColor(color: overlayColor), forKey: kCIInputColorKey)
// 3. 噪点添加 (可选)
// let randomGenerator = CIFilter.randomGenerator()
// let noiseFilter = CIFilter.overlayBlendMode()
// noiseFilter.setValue(randomGenerator.outputImage!, forKey: kCIInputBackgroundImageKey)
// noiseFilter.setValue(overlayFilter.outputImage!, forKey: kCIInputImageKey)
// 获取处理后的图像
guard let outputImage = overlayFilter.outputImage else { return }
guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return }
// 将 CGImage 转换为 UIImage
let processedImage = UIImage(cgImage: cgImage)
// 使用DispatchQueue.main.async 避免UI阻塞
DispatchQueue.main.async {
self.imageView.image = processedImage
}
}
// 设置背景图片
func setBackgroundImage(image: UIImage) {
imageView.image = image
}
}
// 扩展 CIFilter 实现 ColorOverlay 滤镜
extension CIFilter {
class func colorOverlay() -> CIFilter {
guard let filter = CIFilter(name: "CIColorMonochrome") else { fatalError("Unable to create CIColorMonochrome filter.") }
filter.setValue(CIColor(color: UIColor.white), forKey: "inputColor")
filter.setValue(1.0, forKey: "inputIntensity")
return filter
}
}
性能优化:避免卡顿的常见坑点
在使用 Core Image Filters 实现 Liquid Glass 效果时,需要注意性能优化,避免出现卡顿现象。以下是一些常见的坑点和优化建议:
避免频繁创建 CIContext:
CIContext的创建是一个比较耗时的操作,应该尽量避免频繁创建。可以将CIContext创建为单例,或者在视图初始化时创建一次,然后在后续的操作中重复使用。
合理控制模糊半径: 模糊半径越大,计算量越大,性能消耗越高。应该根据实际需求,合理控制模糊半径的大小。
使用异步渲染: 图像处理是一个比较耗时的操作,应该尽量放在后台线程进行处理,避免阻塞主线程。可以使用
DispatchQueue.global().async将图像处理任务放到后台线程执行,然后在主线程更新 UI。缓存处理结果: 如果背景图像不经常变化,可以将处理后的图像缓存起来,避免重复计算。可以使用
NSCache或其他缓存机制来缓存图像。
避免在主线程进行大量的图像计算操作: 图像计算非常消耗 CPU 资源,务必放在子线程中,使用GCD或者OperationQueue都可以。
总结
本文介绍了如何使用 Core Image Filters 实现 Liquid Glass 效果,并提供了一个简单的示例代码。通过合理地组合使用 Core Image Filters,我们可以打造出各种各样炫酷的视觉效果,为 APP 增添更多魅力。下一篇,我们将深入探讨更高级的Liquid Glass效果实现,以及如何在复杂的UI场景中应用这种技术。例如,如何结合 Metal 框架,实现更加高效、流畅的 Liquid Glass 效果。同时,我们也会分享一些在实际项目中的踩坑经验,帮助开发者避免一些常见的错误。
冠军资讯
青衫落拓