如何淡入和淡出UIVisualEffectView和/或UIBlurEffect?


92

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

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

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

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

现在,在两个方向上褪色的工作,但衰落时,它给我一个错误

<UIVisualEffectView 0x7fdf5bcb6e80>被要求动画其不透明度。这将导致效果显示为残破,直到不透明度恢复到1。

我如何成功淡入UIVisualEffectView和淡出而不破坏它并具有淡入淡出的过渡?

注意

  • 我试着将A放进UIVisualEffectViewUIView然后淡入那一个,但没有成功

您可以通过以下方式避免错误:1.不为blurEffect分配初始样式。即,var blurEffectView = UIVisualEffectView(),然后2.在动画块内将blurEffect分配给blurEffectView。3.将“ blurEffect分配给blurEffectView”动画,代替对blurEffectView.alpha的调整。**即使您分配了一个初始值,也将出现错误,将其设置为零,然后将其重新添加。因此,防止错误的关键是在动画块之前,不要将效果分配给blurEffectView。
ObjectiveTC

还需要提及的是,blurEffectView必须具有alpha = 1.0以避免错误。以任何方式篡改alpha都会产生错误。例如,在动画块之前,将blurEffectView.alpha设置为0.7,然后在animationBlock中分配blurEffectView.effect = blurEffect,则会产生错误。
ObjectiveTC

Answers:


185

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

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

将其设置nil为删除。

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


1
完美运作。谢谢。
Baza207 2015年

大!正如您所说,不适用于iOS 8:/
LinusGeffarth,2015年

正是因为我上面写的。我现在还是批准了。@jpros
LinusGeffarth

10
您还可以将效果设置为nil,以获得一个漂亮的“模糊”
jpros 2015年

1
@jpros您介意解释“模糊”的意思吗?
ndmeiri '16

19

苹果的文档(目前)指出...

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

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

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

我建议这样做的目的是避免对于持久视图使用小于1的alpha值。以我的拙见,这不适用于视图的动画。

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

终端消息指出:

要求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编写。)


感谢您的贡献。我明白你的意思;这个错误已经为我解决了,已经有了您提到的确切内容:)
LinusGeffarth,2016年

14

这是我最终使用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
            }
        }
    }

}

您也可以检查要点以找到示例用法。


使用UIViewPropertyAnimator似乎是在iOS 11中唯一可用的东西。谢谢!
LinusGeffarth's

别忘了添加:import UIKit
Oleksandr,

8

只是一种解决方法-放入UIVisualEffectView容器视图并更改alpha该容器的属性。该方法对我在iOS 9上非常有效。似乎在iOS 10中不再起作用。


凉。谢谢,将尝试:)
LinusGeffarth

1
您能否提供示例代码。这似乎不起作用。
cnotethegr8 2015年

在iOS 9
5hrp中

@DerrickHunt在这里也一样。您找到解决方案了吗?
damirstuhec

2
@damirstuhec如果您的项目仅是iOS 10,则可以使用新的UIViewPropertyAnimator类为UIBlurView强度设置动画。如果需要支持较旧的版本,则可以使用上面的代码,并使用#available关键字将UIViewPropertyAnimator用于运行10的设备。希望这对您有所帮助!
德里克·亨特

5

除了控制台中的警告外,您可以更改视觉效果视图的Alpha,而不会出现任何问题。该视图可能看起来只是部分透明的,而不是模糊的。但这通常不成问题,如果您只是在动画过程中更改Alpha。

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


5

您可以拍摄静态基础视图的快照,并在不影响模糊视图的不透明度的情况下对其进行淡入淡出。假设一个不完整的blurView:

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

同样是个不错的主意,但是对于模糊视图下的非静态(移动/动画)内容来说,效果并不理想。
LinusGeffarth

@LinusG。好吧,苹果公司说不应该玩模糊视图alpha。您可以使用CADisplayLink来获取基本视图的屏幕快照,然后在图像视图中渲染它们(也许是您所做的-真正的轻量级)-并在顶视图中显示它们,同时将其不透明度更改为0。可能,但很多工作。
David H

1
(到目前为止)这是我已经能够实现我在​​iOS 10中想要的唯一方法-在全屏模式下淡入淡出,并具有非常暗的模糊效果。谢谢!
格雷厄姆

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组件


2
该问题专门标记为“ swift”,而不是“ objective-c”:请在Swift中提供答案。谢谢!
埃里克·艾雅

1
感谢您的目标C代码。我发现它很方便,因为没有列出许多其他示例。
亚当•韦尔

2

UIVisualEffectView的Alpha始终必须为1。我认为您可以通过设置背景色的Alpha来达到效果。

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


彼得,您能解释一下如何设置背景色的Alpha吗?
鲍里斯Y. 2015年

@borisy colorWithAlphaComponent:UIColor实例上使用该方法。但是,不确定如何通过设置背景色来达到相同的效果。
克星

通过更改背景Alpha组件无法正常工作
Honghao Zhang 2015年


1

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

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,但是这样可以避免错误,并且效果也一样。


1

我只是遇到了这个问题,而解决方法是将UIVisualEffectsView容纳在UIView中,并对UIView的Alpha进行动画处理。

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

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


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.

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()中标记添加的视觉效果视图,以确保在取消模糊处理时唯一删除该效果视图,从而使此功能更强大。 )等,但到目前为止,我还没有发现需要执行这些操作的必要,因为这往往是“一劳永逸”的操作。


“忘了火”是如此相关!哈
LinusGeffarth '17

0

基于@cc的答案,我修改了其扩展名以使视图模糊

扩展UIView {

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

    func unblur(){
        对于子视图中的childView {
            守卫让effectView = childView为?UIVisualEffectView else {继续}
            UIView.animate(withDuration:2.5,animations:{
                effectView.effect =无
            }){
                didFinish in
                effectView.removeFromSuperview()
            }
        }
    }
}

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()因为它将覆盖动画。另外,在模拟器上运行时,将图形转到更高的级别可以查看动画(“调试”>“图形质量替代”>“高质量”)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.