在iOS中,通常是使用UIVisualEffectView
+UIBlurEffect
实现毛玻璃效果,但是苹果并没有提供修改模糊度的API。网上很多都是修改其alpha
值实现所谓“模糊度改变”的效果,这种只是自欺欺人的做法,并非真的修改了模糊度。
Demo地址:JPBlurView
实现毛玻璃动画
虽说没有修改模糊度的API,但是有毛玻璃的展示和隐藏动画:
let effectView = UIVisualEffectView(effect: nil)
// 毛玻璃展示动画
UIView.animate(withDuration: 0.3) {
effectView.effect = UIBlurEffect(style: systemThinMaterialDark)
}
// 毛玻璃隐藏动画
UIView.animate(withDuration: 0.3) {
effectView.effect = nil
}
只要对UIVisualEffectView
的effect
属性的setter方法包裹一层动画,就可以实现毛玻璃动画了:
控制毛玻璃动画进度
仔细观察,这个毛玻璃效果从无到有这个过程,不就是模糊度从0到1的过程吗?那么只要能控制这个毛玻璃动画的进度,就相当于自定义模糊度了。这种情况就是UIViewPropertyAnimator
登场的时候了。
UIViewPropertyAnimator
是iOS中的一个动画类,用于创建和管理视图动画。它提供了一种强大且灵活的方式来创建自定义的交互式动画:可以定义动画的起始状态、结束状态和持续时间,还可以通过控制动画的进度来实现交互性。
更多的介绍这里就不赘述了,网上很多资料可以参考,这里简单实现一下:
let effectView = UIVisualEffectView(effect: nil)
animator = UIViewPropertyAnimator(duration: 0, curve: .linear, animations: { [weak effectView] in
effectView?.effect = UIBlurEffect(style: systemThinMaterialDark)
})
animator.fractionComplete = 0
这样,通过修改animator
的fractionComplete
属性从而实现可自定义模糊度的毛玻璃效果了:
实现可自定义模糊度动画
虽然UIViewPropertyAnimator
可以控制动画进度,但是并不能实现自定义模糊度的动画。
例如如果想通过UIViewPropertyAnimator
实现模糊度0.2~0.7的动画是不行的,一旦动画开始了就会直达1.0,不能执行到某个值自动停下,除非对fractionComplete
属性进行监听,我个人觉得这种做法很麻烦。
有没有一种模拟动画并且能返回动画进度的方法呢?这样我就能通过这个实时动画进度更新fractionComplete
属性就可以了。
很幸运,有!那就是pop!
POPPropertyAnimation
有个POPAnimatableProperty
属性,可以实时监听动画的进度,而且是带有动画曲线的进度,并且不需要真的对某个视图添加动画,简单来说就是能模拟一个动画,十分好用。
我这里选择使用POPBasicAnimation
来实现,因为POPBasicAnimation
能自定义动画时长和动画曲线,能满足基本的动画效果:
// 创建一个基类专门来监听进度
let animObserver = NSObject()
let animation = POPBasicAnimation()
animation.fromValue = 0.2
animation.toValue = 0.7
animation.duration = 0.3
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
// 监听实时动画进度
animation.property = POPAnimatableProperty.property(withName: "JPProperty") { [weak animator] prop in
prop?.writeBlock = { (_, values) in
guard let values = values else { return }
let value = values[0]
// 刷新模糊度
animator?.fractionComplete = value
}
} as? POPAnimatableProperty
// 开始(模拟)动画
animObserver.pop_add(animation, forKey: "JPAnimation")
这样就能实现可自定义模糊度动画了:
需要注意的地方
- 一旦使用
UIViewPropertyAnimator
暂停了动画(没有开启或还没结束),必须在退出页面前让动画结束,否则会崩溃!
animator.stopAnimation(true)
- 同样,如果使用
UIViewPropertyAnimator
暂停了动画,App一旦进入后台模式就会失效(挂起时不会),返回前台时需要重新设置一下:
@objc func willEnterForegroundHandle() {
guard animator.state != .active else { return }
animator.stopAnimation(true)
resetAnimator()
}
实现可交互的毛玻璃背景
结合上面的做法,就可以在浏览大图的背景实现这种可交互的毛玻璃效果了:
- 通过手指进行交互,根据手指滑动距离修改模糊度;
- 松开手指还原/关闭,动画实现模糊度从0.x到1.0/0.0的过程。
Demo地址:JPBlurView