94

我想淡入淡出带有 UIBlurEffect 的 UIVisualEffectsView :

var blurEffectView = UIVisualEffectView()
blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))

我在由 a 调用的函数中使用普通动画将UIButton其淡入,淡出相同,但.alpha = 0& hidden = true

blurEffectView.hidden = false
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut) {
    self.blurEffectView.alpha = 1
}

现在,在两个方向上淡出确实有效,但是淡出时它给了我一个错误

<UIVisualEffectView 0x7fdf5bcb6e80>被要求为其不透明度设置动画。这将导致效果出现损坏,直到不透明度恢复为 1。

问题

我如何成功地淡入UIVisualEffectView和淡出而不破坏它并进行淡入淡出过渡?

笔记

  • 我试图把它UIVisualEffectView变成一个UIView并淡化那个,没有成功
4

15 回答 15

191

我认为这是 iOS9 中的新功能,但您现在可以UIVisualEffectView在动画块内设置 a 的效果:

let overlay = UIVisualEffectView()
// Put it somewhere, give it a frame...
UIView.animate(withDuration: 0.5) {
    overlay.effect = UIBlurEffect(style: .light)
}

将其设置nil为删除。

非常重要 - 在模拟器上进行测试时,请确保将模拟器的图形质量覆盖设置为高质量以使其正常工作。

于 2015-09-25T11:00:45.530 回答
19

Apple 文档(当前)指出...

使用 UIVisualEffectView 类时,避免小于 1 的 alpha 值。

在视觉效果视图或其任何超级视图上将 alpha 设置为小于 1 会导致许多效果看起来不正确或根本不显示。

我相信这里缺少一些重要的背景......

我建议这样做的目的是避免 alpha 值小于 1 以获得持久视图。在我看来,这不适用于视图的动画。

我的观点 - 我建议小于 1 的 alpha 值对于动画是可以接受的。

终端消息指出:

UIVisualEffectView 被要求为其不透明度设置动画。这将导致效果出现损坏,直到不透明度恢复为 1。

仔细读到这里,效果会显得很破。我的观点是:

  • 明显的中断仅对于持久的视图才真正重要 - 不会改变;
  • UIVisualEffectalpha 值小于 1的持久/不变视图将不会按照 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.

请注意,将 设置effectnil在动画结束时会创建一个“漂亮的闪光”(需要更好的描述),而将 设置alpha0创建一个平滑的过渡。

(让我知道任何语法错误......我用 obj-c 编写。)

于 2016-03-26T00:45:13.077 回答
15

这是我最终的解决方案,它适用于使用 Swift 3 的 iOS10 和更早版本

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
            }
        }
    }

}

您还可以查看此要点以查找示例用法。

于 2017-02-16T13:53:00.750 回答
8

只是一种解决方法 - 放入UIVisualEffectView容器视图并更改alpha该容器的属性。这种方法在 iOS 9 上非常适合我。似乎它不再适用于 iOS 10。

于 2015-07-09T13:43:36.393 回答
5

除了控制台中的警告之外,您可以毫无问题地更改视觉效果视图的 alpha。视图可能看起来只是部分透明,而不是模糊。但是,如果您只是在动画期间更改 alpha,这通常不是问题。

您的应用不会因此崩溃或被拒绝。在真实设备(或八个)上进行测试。如果您对它的外观和性能感到满意,那很好。Apple 只是警告您,它的外观或性能可能不如 alpha 值为 1 的视觉效果视图。

于 2015-05-13T17:45:41.693 回答
5

您可以拍摄静态底层视图的快照,并在不触及模糊视图的不透明度的情况下将其淡入淡出。假设 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()
    } )
}
于 2015-07-29T18:45:57.010 回答
3

如果你想淡入你的 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 组件

于 2016-12-07T09:54:41.487 回答
2

UIVisualEffectView 的 alpha 始终必须为 1。我认为您可以通过设置背景颜色的 alpha 来实现效果。

来源:https ://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html

于 2015-03-27T18:53:21.297 回答
1

我刚刚遇到了这个问题,我解决它的方法是将 UIVisualEffectsView 放在 UIView 中,并为 UIView 的 alpha 设置动画。

这效果很好,只是它一旦 alpha 变为低于 1.0,它就会变成纯白色,看起来非常刺耳。为了解决这个问题,您必须设置 UIView 的 layer 属性containerView.layer.allowsGroupOpacity = false,这将防止它闪烁白色。

现在您可以使用它的 alpha 属性为包含视觉效果视图和任何其他子视图的 UIView 设置动画/淡出,而不必担心任何图形故障或它会记录警告消息。

于 2017-06-13T23:38:30.993 回答
1

我最终得到了以下解决方案,对 UIVisualEffectView和 内容使用单独的动画。我使用该viewWithTag()方法来获取UIViewUIVisualEffectView.

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 的单个动画,但这可以避免错误并且似乎也可以正常工作。

于 2015-11-06T02:13:39.357 回答
1

我制作了一个 alpha 为 0 的 uiview 并添加了 blurview 作为它的子视图。所以我可以用动画隐藏/显示或圆角它。

于 2015-12-02T07:38:43.713 回答
0

基于@cc's answer我修改了他的扩展以模糊视图

扩展 UIView {

    功能模糊(){
        // 模糊当前视图
        让 blurView = UIVisualEffectView(frame: self.bounds)
        self.addSubview(blurView)
        UIView.animate(withDuration:0.25) {
            blurView.effect = UIBlurEffect(样式:.dark)
        }
    }

    函数 unblur() {
        对于子视图中的 childView {
            守卫让 effectView = childView 作为?UIVisualEffectView else { 继续 }
            UIView.animate(withDuration:2.5,动画:{
                effectView.effect = nil
            }) {
                完成了
                effectView.removeFromSuperview()
            }
        }
    }
}
于 2018-08-30T12:45:39.140 回答
0
_visualEffectView.contentView.alpha = 0;

要改变 UIVisualEffectView 的 alpha,你应该改变 _visualEffectView 的 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.
于 2016-03-29T09:53:16.863 回答
0

通常,当我在屏幕上呈现视图控制器并想要模糊呈现视图控制器时,我只想为模糊设置动画。这是一个将 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( ) 等,但到目前为止我还没有发现需要做这些事情,因为这往往是一种“一劳永逸”的操作。

于 2017-05-30T18:44:15.313 回答
0

改进@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()因为它会覆盖动画。此外,在模拟器上运行时,将图形调到更高级别以便能够看到动画(调试 > 图形质量覆盖 > 高质量)。

于 2018-09-13T09:06:55.300 回答