如何淡入淡出 UIVisualEffectView and/or UIBlurEffect?
How to fade a UIVisualEffectView and/or UIBlurEffect in and out?
我想淡入淡出带有 UIBlurEffect 的 UIVisualEffectsView:
var blurEffectView = UIVisualEffectView()
blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
我在 UIButton
调用的函数中使用普通动画来淡入,淡出也是如此,但是 .alpha = 0
& hidden = true
:
blurEffectView.hidden = false
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut) {
self.blurEffectView.alpha = 1
}
现在,双向淡入淡出确实有效,但在淡入时出现错误 out:
<UIVisualEffectView 0x7fdf5bcb6e80>
is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
问题
如何成功地使 UIVisualEffectView
淡入和淡出而不 破坏 它并进行淡入淡出过渡?
备注
- 我尝试将
UIVisualEffectView
放入 UIView
并淡化那个,但没有成功
UIVisualEffectView 的 alpha 必须始终为 1。我认为您可以通过设置背景颜色的 alpha 来实现效果。
来源:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html
除了控制台中的警告外,您可以毫无问题地更改视觉效果视图的 alpha。视图可能看起来只是部分透明,而不是模糊。但如果您只是在动画期间更改 alpha,这通常不是问题。
您的应用不会因此崩溃或被拒绝。在真实设备(或八台)上测试它。如果您对它的外观和性能感到满意,那很好。 Apple 只是警告您,它的外观或性能可能不如 alpha 值为 1 的视觉效果视图。
只是一个解决方法 - 将 UIVisualEffectView
放入容器视图并为该容器更改 alpha
属性。这种方法在 iOS 9 上非常适合我。似乎它在 iOS 10.
上不再有效
您可以拍摄静态底层视图的快照,并在不影响模糊视图的不透明度的情况下淡入淡出。假设一个 blurView 的 ivar:
func addBlur() {
guard let blurEffectView = blurEffectView else { return }
//snapShot = UIScreen.mainScreen().snapshotViewAfterScreenUpdates(false)
let snapShot = self.view.snapshotViewAfterScreenUpdates(false)
view.addSubview(blurEffectView)
view.addSubview(snapShot)
UIView.animateWithDuration(0.25, animations: {
snapShot.alpha = 0.0
}, completion: { (finished: Bool) -> Void in
snapShot.removeFromSuperview()
} )
}
func removeBlur() {
guard let blurEffectView = blurEffectView else { return }
let snapShot = self.view.snapshotViewAfterScreenUpdates(false)
snapShot.alpha = 0.0
view.addSubview(snapShot)
UIView.animateWithDuration(0.25, animations: {
snapShot.alpha = 1.0
}, completion: { (finished: Bool) -> Void in
blurEffectView.removeFromSuperview()
snapShot.removeFromSuperview()
} )
}
我认为这是 iOS9 中的新功能,但您现在可以在动画块中设置 UIVisualEffectView
的效果:
let overlay = UIVisualEffectView()
// Put it somewhere, give it a frame...
UIView.animate(withDuration: 0.5) {
overlay.effect = UIBlurEffect(style: .light)
}
将其设置为 nil
以删除。
非常重要 - 在模拟器上进行测试时,请确保将模拟器的图形质量覆盖设置为高质量,这样才能正常工作。
我最终得到以下解决方案,为 UIVisualEffectView
和内容使用单独的动画。我使用 viewWithTag()
方法获取对 UIVisualEffectView
.
中 UIView
的引用
let blurEffectView = UIVisualEffectView()
// Fade in
UIView.animateWithDuration(1) { self.blurEffectView.effect = UIBlurEffect(style: .Light) }
UIView.animateWithDuration(1) { self.blurEffectView.viewWithTag(1)?.alpha = 1 }
// Fade out
UIView.animateWithDuration(1) { self.blurEffectView.effect = nil }
UIView.animateWithDuration(1) { self.blurEffectView.viewWithTag(1)?.alpha = 0 }
我更喜欢改变 alpha 的单个动画,但这避免了错误并且似乎也能正常工作。
我制作了一个 alpha 为 0 的 uiview,并将 blurview 添加为它的子视图。所以我可以 hide/show 或用动画圆角它。
Apple documentation(当前)状态...
When using the UIVisualEffectView class, avoid alpha values that are less than 1.
和
Setting the alpha to less than 1 on the visual effect view or any of its superviews causes many effects to look incorrect or not show up at all.
我认为这里缺少一些重要的上下文...
我建议的目的是避免持久视图的 alpha 值小于 1。以我的拙见,这不适用于视图的动画。
我的观点 - 我建议动画可以接受小于 1 的 alpha 值。
终端消息指出:
UIVisualEffectView is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
仔细阅读这个,效果会出现被打破。我对此的看法是:
- 明显的中断只对持久不变的视图真正重要;
- alpha 值小于 1 的持久/不变
UIVisualEffect
视图将不会按 Apple 的预期/设计呈现;和
- 终端中的消息不是错误,只是警告。
为了扩展@jrturton 上面帮助我解决问题的答案,我会添加...
要淡出 UIVisualEffect
使用以下 (Objective-C) 代码:
UIView.animateWithDuration(1.0, animations: {
// EITHER...
self.blurEffectView.effect = UIBlurEffect(nil)
// OR...
self.blurEffectView.alpha = 0
}, completion: { (finished: Bool) -> Void in
self.blurEffectView.removeFromSuperview()
} )
我成功地使用了两种方法:将 effect
属性 设置为 nil
并将 alpha
属性 设置为 0
。
请注意,将 effect
设置为 nil
会在动画结束时创建一个 "nice flash"(为了更好的描述),同时设置 alpha
到 0
创建平滑过渡。
(让我知道任何语法错误...我用 obj-c 编写。)
_visualEffectView.contentView.alpha = 0;
要改变 UIVisualEffectView 的 alpha,你应该改变 _visualEffectView.If 的 contentView 你改变 _visualEffectView 的 alpha,你会得到这个
<UIVisualEffectView 0x7ff7bb54b490> is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
如果您想淡入 UIVisualEffectView - ios10 使用 UIViewPropertyAnimator
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:nil];
blurEffectView.frame = self.view.frame;
blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UIView *blackUIView = [[UIView alloc]initWithFrame:self.view.frame];
[bacgroundImageView addSubview:blackUIView];
[blackUIView addSubview:blurEffectView];
UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc] initWithDuration:4.f curve:UIViewAnimationCurveLinear animations:^{
[blurEffectView setEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
}];
然后你可以设置百分比
[animator setFractionComplete:percent];
对于 ios9 你可以使用 alpha 组件
这是我最终得到的解决方案,它适用于 iOS10 和使用 Swift 3
的早期版本
extension UIVisualEffectView {
func fadeInEffect(_ style:UIBlurEffectStyle = .light, withDuration duration: TimeInterval = 1.0) {
if #available(iOS 10.0, *) {
let animator = UIViewPropertyAnimator(duration: duration, curve: .easeIn) {
self.effect = UIBlurEffect(style: style)
}
animator.startAnimation()
}else {
// Fallback on earlier versions
UIView.animate(withDuration: duration) {
self.effect = UIBlurEffect(style: style)
}
}
}
func fadeOutEffect(withDuration duration: TimeInterval = 1.0) {
if #available(iOS 10.0, *) {
let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
self.effect = nil
}
animator.startAnimation()
animator.fractionComplete = 1
}else {
// Fallback on earlier versions
UIView.animate(withDuration: duration) {
self.effect = nil
}
}
}
}
您还可以check this gist查找示例用法。
通常,我只想在屏幕上呈现视图控制器时制作模糊动画,并想模糊呈现的视图控制器。这是一个将 blur() 和 unblur() 添加到视图控制器以促进这一点的扩展:
extension UIViewController {
func blur() {
// Blur out the current view
let blurView = UIVisualEffectView(frame: self.view.frame)
self.view.addSubview(blurView)
UIView.animate(withDuration:0.25) {
blurView.effect = UIBlurEffect(style: .light)
}
}
func unblur() {
for childView in view.subviews {
guard let effectView = childView as? UIVisualEffectView else { continue }
UIView.animate(withDuration: 0.25, animations: {
effectView.effect = nil
}) {
didFinish in
effectView.removeFromSuperview()
}
}
}
}
当然,您可以让用户选择效果样式、修改持续时间、在动画完成时调用一些东西、在 blur() 中标记添加的视觉效果视图以确保它是唯一的,从而使它更健壮当你 unblur() 等时删除,但到目前为止我还没有发现需要做这些事情,因为这往往是一种 "fire and forget" 类型的操作。
我刚遇到这个问题,我解决这个问题的方法是将 UIVisualEffectsView 放在 UIView 中,并为该 UIView 的 alpha 设置动画。
这很好用,只是一旦 alpha 低于 1.0,它就会变成纯白色,看起来非常刺耳。为了解决这个问题,您必须设置 UIView 的图层 属性 containerView.layer.allowsGroupOpacity = false
,这将防止它闪烁白色。
现在您可以使用它的 alpha 属性 动画 in/fade 包含视觉效果视图和任何其他子视图的 UIView,而不必担心任何图形故障或记录警告消息。
根据@cc 的回答,我修改了他的扩展以模糊视图
extension UIView {
func blur() {
// Blur out the current view
let blurView = UIVisualEffectView(frame: self.bounds)
self.addSubview(blurView)
UIView.animate(withDuration:0.25) {
blurView.effect = UIBlurEffect(style: .dark)
}
}
func unblur() {
for childView in subviews {
guard let effectView = childView as? UIVisualEffectView else { continue }
UIView.animate(withDuration: 2.5, animations: {
effectView.effect = nil
}) {
didFinish in
effectView.removeFromSuperview()
}
}
}
}
改进@Tel4tel 和@cc 响应,这里是一个带有参数的扩展和一个简短的解释。
extension UIView {
// Perform a blur animation in the whole view
// Effect tone can be .light, .dark, .regular...
func blur(duration inSeconds: Double, effect tone: UIBlurEffectStyle) {
let blurView = UIVisualEffectView(frame: self.bounds)
self.addSubview(blurView)
UIView.animate(withDuration: inSeconds) {
blurView.effect = UIBlurEffect(style: tone)
}
}
// Perform an unblur animation in the whole view
func unblur(duration inSeconds: Double) {
for childView in subviews {
guard let effectView = childView as? UIVisualEffectView else { continue
}
UIView.animate(withDuration: inSeconds, animations: {
effectView.effect = nil
}){
didFinish in effectView.removeFromSuperview()
}
}
}
}
然后你可以像这样使用它:
view.blur(duration: 5.0, effect: .light)
要么
view.unblur(duration: 3.0)
切记不要在 viewDidLoad()
中使用它,因为它会覆盖动画。
此外,当 运行 在模拟器上时,将图形调到更高级别以便能够看到动画(调试 > 图形质量覆盖 > 高质量)。
我想淡入淡出带有 UIBlurEffect 的 UIVisualEffectsView:
var blurEffectView = UIVisualEffectView()
blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
我在 UIButton
调用的函数中使用普通动画来淡入,淡出也是如此,但是 .alpha = 0
& hidden = true
:
blurEffectView.hidden = false
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut) {
self.blurEffectView.alpha = 1
}
现在,双向淡入淡出确实有效,但在淡入时出现错误 out:
<UIVisualEffectView 0x7fdf5bcb6e80>
is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
问题
如何成功地使 UIVisualEffectView
淡入和淡出而不 破坏 它并进行淡入淡出过渡?
备注
- 我尝试将
UIVisualEffectView
放入UIView
并淡化那个,但没有成功
UIVisualEffectView 的 alpha 必须始终为 1。我认为您可以通过设置背景颜色的 alpha 来实现效果。
来源:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html
除了控制台中的警告外,您可以毫无问题地更改视觉效果视图的 alpha。视图可能看起来只是部分透明,而不是模糊。但如果您只是在动画期间更改 alpha,这通常不是问题。
您的应用不会因此崩溃或被拒绝。在真实设备(或八台)上测试它。如果您对它的外观和性能感到满意,那很好。 Apple 只是警告您,它的外观或性能可能不如 alpha 值为 1 的视觉效果视图。
只是一个解决方法 - 将 UIVisualEffectView
放入容器视图并为该容器更改 alpha
属性。这种方法在 iOS 9 上非常适合我。似乎它在 iOS 10.
您可以拍摄静态底层视图的快照,并在不影响模糊视图的不透明度的情况下淡入淡出。假设一个 blurView 的 ivar:
func addBlur() {
guard let blurEffectView = blurEffectView else { return }
//snapShot = UIScreen.mainScreen().snapshotViewAfterScreenUpdates(false)
let snapShot = self.view.snapshotViewAfterScreenUpdates(false)
view.addSubview(blurEffectView)
view.addSubview(snapShot)
UIView.animateWithDuration(0.25, animations: {
snapShot.alpha = 0.0
}, completion: { (finished: Bool) -> Void in
snapShot.removeFromSuperview()
} )
}
func removeBlur() {
guard let blurEffectView = blurEffectView else { return }
let snapShot = self.view.snapshotViewAfterScreenUpdates(false)
snapShot.alpha = 0.0
view.addSubview(snapShot)
UIView.animateWithDuration(0.25, animations: {
snapShot.alpha = 1.0
}, completion: { (finished: Bool) -> Void in
blurEffectView.removeFromSuperview()
snapShot.removeFromSuperview()
} )
}
我认为这是 iOS9 中的新功能,但您现在可以在动画块中设置 UIVisualEffectView
的效果:
let overlay = UIVisualEffectView()
// Put it somewhere, give it a frame...
UIView.animate(withDuration: 0.5) {
overlay.effect = UIBlurEffect(style: .light)
}
将其设置为 nil
以删除。
非常重要 - 在模拟器上进行测试时,请确保将模拟器的图形质量覆盖设置为高质量,这样才能正常工作。
我最终得到以下解决方案,为 UIVisualEffectView
和内容使用单独的动画。我使用 viewWithTag()
方法获取对 UIVisualEffectView
.
UIView
的引用
let blurEffectView = UIVisualEffectView()
// Fade in
UIView.animateWithDuration(1) { self.blurEffectView.effect = UIBlurEffect(style: .Light) }
UIView.animateWithDuration(1) { self.blurEffectView.viewWithTag(1)?.alpha = 1 }
// Fade out
UIView.animateWithDuration(1) { self.blurEffectView.effect = nil }
UIView.animateWithDuration(1) { self.blurEffectView.viewWithTag(1)?.alpha = 0 }
我更喜欢改变 alpha 的单个动画,但这避免了错误并且似乎也能正常工作。
我制作了一个 alpha 为 0 的 uiview,并将 blurview 添加为它的子视图。所以我可以 hide/show 或用动画圆角它。
Apple documentation(当前)状态...
When using the UIVisualEffectView class, avoid alpha values that are less than 1.
和
Setting the alpha to less than 1 on the visual effect view or any of its superviews causes many effects to look incorrect or not show up at all.
我认为这里缺少一些重要的上下文...
我建议的目的是避免持久视图的 alpha 值小于 1。以我的拙见,这不适用于视图的动画。
我的观点 - 我建议动画可以接受小于 1 的 alpha 值。
终端消息指出:
UIVisualEffectView is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
仔细阅读这个,效果会出现被打破。我对此的看法是:
- 明显的中断只对持久不变的视图真正重要;
- alpha 值小于 1 的持久/不变
UIVisualEffect
视图将不会按 Apple 的预期/设计呈现;和 - 终端中的消息不是错误,只是警告。
为了扩展@jrturton 上面帮助我解决问题的答案,我会添加...
要淡出 UIVisualEffect
使用以下 (Objective-C) 代码:
UIView.animateWithDuration(1.0, animations: {
// EITHER...
self.blurEffectView.effect = UIBlurEffect(nil)
// OR...
self.blurEffectView.alpha = 0
}, completion: { (finished: Bool) -> Void in
self.blurEffectView.removeFromSuperview()
} )
我成功地使用了两种方法:将 effect
属性 设置为 nil
并将 alpha
属性 设置为 0
。
请注意,将 effect
设置为 nil
会在动画结束时创建一个 "nice flash"(为了更好的描述),同时设置 alpha
到 0
创建平滑过渡。
(让我知道任何语法错误...我用 obj-c 编写。)
_visualEffectView.contentView.alpha = 0;
要改变 UIVisualEffectView 的 alpha,你应该改变 _visualEffectView.If 的 contentView 你改变 _visualEffectView 的 alpha,你会得到这个
<UIVisualEffectView 0x7ff7bb54b490> is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
如果您想淡入 UIVisualEffectView - ios10 使用 UIViewPropertyAnimator
UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:nil];
blurEffectView.frame = self.view.frame;
blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UIView *blackUIView = [[UIView alloc]initWithFrame:self.view.frame];
[bacgroundImageView addSubview:blackUIView];
[blackUIView addSubview:blurEffectView];
UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc] initWithDuration:4.f curve:UIViewAnimationCurveLinear animations:^{
[blurEffectView setEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
}];
然后你可以设置百分比
[animator setFractionComplete:percent];
对于 ios9 你可以使用 alpha 组件
这是我最终得到的解决方案,它适用于 iOS10 和使用 Swift 3
的早期版本extension UIVisualEffectView {
func fadeInEffect(_ style:UIBlurEffectStyle = .light, withDuration duration: TimeInterval = 1.0) {
if #available(iOS 10.0, *) {
let animator = UIViewPropertyAnimator(duration: duration, curve: .easeIn) {
self.effect = UIBlurEffect(style: style)
}
animator.startAnimation()
}else {
// Fallback on earlier versions
UIView.animate(withDuration: duration) {
self.effect = UIBlurEffect(style: style)
}
}
}
func fadeOutEffect(withDuration duration: TimeInterval = 1.0) {
if #available(iOS 10.0, *) {
let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
self.effect = nil
}
animator.startAnimation()
animator.fractionComplete = 1
}else {
// Fallback on earlier versions
UIView.animate(withDuration: duration) {
self.effect = nil
}
}
}
}
您还可以check this gist查找示例用法。
通常,我只想在屏幕上呈现视图控制器时制作模糊动画,并想模糊呈现的视图控制器。这是一个将 blur() 和 unblur() 添加到视图控制器以促进这一点的扩展:
extension UIViewController {
func blur() {
// Blur out the current view
let blurView = UIVisualEffectView(frame: self.view.frame)
self.view.addSubview(blurView)
UIView.animate(withDuration:0.25) {
blurView.effect = UIBlurEffect(style: .light)
}
}
func unblur() {
for childView in view.subviews {
guard let effectView = childView as? UIVisualEffectView else { continue }
UIView.animate(withDuration: 0.25, animations: {
effectView.effect = nil
}) {
didFinish in
effectView.removeFromSuperview()
}
}
}
}
当然,您可以让用户选择效果样式、修改持续时间、在动画完成时调用一些东西、在 blur() 中标记添加的视觉效果视图以确保它是唯一的,从而使它更健壮当你 unblur() 等时删除,但到目前为止我还没有发现需要做这些事情,因为这往往是一种 "fire and forget" 类型的操作。
我刚遇到这个问题,我解决这个问题的方法是将 UIVisualEffectsView 放在 UIView 中,并为该 UIView 的 alpha 设置动画。
这很好用,只是一旦 alpha 低于 1.0,它就会变成纯白色,看起来非常刺耳。为了解决这个问题,您必须设置 UIView 的图层 属性 containerView.layer.allowsGroupOpacity = false
,这将防止它闪烁白色。
现在您可以使用它的 alpha 属性 动画 in/fade 包含视觉效果视图和任何其他子视图的 UIView,而不必担心任何图形故障或记录警告消息。
根据@cc 的回答,我修改了他的扩展以模糊视图
extension UIView { func blur() { // Blur out the current view let blurView = UIVisualEffectView(frame: self.bounds) self.addSubview(blurView) UIView.animate(withDuration:0.25) { blurView.effect = UIBlurEffect(style: .dark) } } func unblur() { for childView in subviews { guard let effectView = childView as? UIVisualEffectView else { continue } UIView.animate(withDuration: 2.5, animations: { effectView.effect = nil }) { didFinish in effectView.removeFromSuperview() } } } }
改进@Tel4tel 和@cc 响应,这里是一个带有参数的扩展和一个简短的解释。
extension UIView {
// Perform a blur animation in the whole view
// Effect tone can be .light, .dark, .regular...
func blur(duration inSeconds: Double, effect tone: UIBlurEffectStyle) {
let blurView = UIVisualEffectView(frame: self.bounds)
self.addSubview(blurView)
UIView.animate(withDuration: inSeconds) {
blurView.effect = UIBlurEffect(style: tone)
}
}
// Perform an unblur animation in the whole view
func unblur(duration inSeconds: Double) {
for childView in subviews {
guard let effectView = childView as? UIVisualEffectView else { continue
}
UIView.animate(withDuration: inSeconds, animations: {
effectView.effect = nil
}){
didFinish in effectView.removeFromSuperview()
}
}
}
}
然后你可以像这样使用它:
view.blur(duration: 5.0, effect: .light)
要么
view.unblur(duration: 3.0)
切记不要在 viewDidLoad()
中使用它,因为它会覆盖动画。
此外,当 运行 在模拟器上时,将图形调到更高级别以便能够看到动画(调试 > 图形质量覆盖 > 高质量)。