【问题标题】:Presenting View Controller with Blur Effect呈现具有模糊效果的视图控制器
【发布时间】:2016-09-22 16:54:24
【问题描述】:

我正在以模态方式呈现具有模糊背景效果的视图控制器。 iOS 10/XCode 8 给我的动画带来了问题。这是演示代码:

let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
modalVC.modalTransitionStyle = .CrossDissolve
modalVC.modalPresentationStyle = .OverFullScreen
presentViewController(modalVC, animated: true, completion: nil)

在 ModalViewController 中的 viewDidLoad() 函数上添加模糊:

let blurEffect = UIBlurEffect(style: .Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = view.bounds
blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

view.addSubview(blurEffectView)
view.sendSubviewToBack(blurEffectView)

ModalViewController 具有清晰的背景,我添加了带有深色模糊效果的 BlurEffectView。使用以前的 sn-p 和 Interface Builder 以编程方式进行了尝试。

在 iOS 8 和 9 上,.CrossDissolve 过渡处理了“淡入淡出”,但在 iOS 10(设备和模拟器)上进行测试后,视图以深色的半透明背景色显示,而不是模糊。

.CrossDissolve 动画结束后,背景颜色变为实际的模糊效果背景。任何想法为什么会发生这种情况?

还尝试在viewDidLoad() 的开头和结尾添加layoutIfNeeded() 用于模态视图控制器,但没有任何运气。我正在使用 swift 2.3

【问题讨论】:

  • 也发现了这种令人讨厌的行为变化。您是否尝试过关闭过渡样式并手动处理动画?
  • 试过了,看起来好多了,但是模糊还是有一点延迟。只是不那么引人注目
  • 有一个可禁用模糊的辅助功能,适合那些忘记这一点的人。 OP也是+1,我也有同样的问题。我在呈现的 VC 后面有一个带有自定义单元格的表格视图。模糊只适用于交叉溶解动画结束后的东西,然后突然模糊呈现的VC。

标签: ios iphone swift xcode8 uiblureffect


【解决方案1】:
你好,

您需要创建一个新的UIViewControllerAnimatedTransitioning

然后在animateTransition(using transitionContext: UIViewControllerContextTransitioning) 中,您需要对动画进行编码。

现在,在 iOS 10 中,您可以使用 UIViewPropertyAnimatorUIVisualBlurEffectBlurRadius 设置动画。

结果:

这里有一个使用示例:https://github.com/PierrePerrin/PPBlurModalPresentation

首先

你需要创建你的模糊过渡

    class BlurModalPresentation: NSObject,UIViewControllerAnimatedTransitioning {


        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval{

            return 0.5
        }

//This is the blur view used for transition
        var blurView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
        var destinationView : UIView!
        var animator: UIViewPropertyAnimator?

        // This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning){

            let containerView = transitionContext.containerView

            _ = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
            let toVc = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)

            destinationView = toVc!.view
            destinationView.alpha = 0.0

//Here we add the blur view and set it effect to nil
            blurView.effect = nil
            blurView.frame = containerView.bounds

            self.blurTransition(transitionContext) { 

                self.unBlur(transitionContext, completion: { 

                    self.blurView.removeFromSuperview()
                    transitionContext.completeTransition(true)
                })
            }

            containerView.addSubview(toVc!.view)
            containerView.addSubview(blurView)
        }

        //This methods add the blur to our view and our destinationView
        func blurTransition(_ context : UIViewControllerContextTransitioning,completion: @escaping () -> Void){

            UIViewPropertyAnimator.runningPropertyAnimator(withDuration: self.transitionDuration(using: context)/2, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {

                self.destinationView.alpha = 0.5
                  self.blurView.effect = UIBlurEffect(style: UIBlurEffectStyle.light)
            }, completion: { (position) in
                completion()
            })

        }
        //This Method remove the blur view with an animation
        func unBlur(_ context : UIViewControllerContextTransitioning,completion: @escaping () -> Void){

            UIViewPropertyAnimator.runningPropertyAnimator(withDuration: self.transitionDuration(using: context) / 2, delay:0, options: UIViewAnimationOptions.curveLinear, animations: {

                self.destinationView.alpha = 1.0
                self.blurView.effect = nil
            }, completion: { (position) in
                completion()
            })
        }

    }

那么

您需要在ViewController 中设置过渡委托:

import UIKit

class ViewController: UIViewController,UIViewControllerTransitioningDelegate {

    let blurModalPresentation = BlurModalPresentation()

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    func showVC(){

        let str = self.storyboard!
        let vc = str.instantiateViewController(withIdentifier: "YourViewControllerIdentifier")
        vc.transitioningDelegate = self
        self.present(vc, animated: true, completion: nil)
    }


    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?{

        return blurModalPresentation
    }


    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?{

        return blurModalPresentation
    }

}

【讨论】:

    【解决方案2】:

    首先,我将此解决方案视为一种临时解决方法,因为我必须假设这种新引入的行为是一个错误,并将在未来的更新中修复。这使得它稍微不那么明显,因为模糊效果在动画期间而不是之后突然出现。仍然不如 iOS 9 及更低版本,但稍微好一些。

    1. 显示没有动画的视图控制器:

      presentViewController(modalVC, animated: false, completion: nil)
      
    2. 从一开始就隐藏你的视图:

      override func viewDidLoad() {
          super.viewDidLoad()
      
          view.alpha = 0
      }
      
    3. 手动应用动画:

      override func viewWillAppear(animated: Bool) {
          super.viewWillAppear(animated)
      
          UIView.animateWithDuration(0.25) {
              self.view.alpha = 1
          }
      }
      
      override func viewWillDisappear(animated: Bool) {
          super.viewWillDisappear(animated)
      
          UIView.animateWithDuration(0.25) {
              self.view.alpha = 0
          }
      }
      

    【讨论】:

    • 是的,这似乎是目前唯一的解决方法,不过额外的延迟有点烦人。在接受希望有人可能会提出替代解决方案之前,我将把这个问题留待一段时间。
    • 我理解您的意思,但您可能需要将步骤 1 编辑为 presentViewController(modalVC, animated: false, completion: nil)
    • 糟糕,谢谢@Fdo!将animated 更改为false。我不希望将这个答案选为解决方案,因为它远非完美无缺。也希望有人想出更好的东西!
    【解决方案3】:

    唯一正确的方法是创建自定义模态过渡和动画效果属性。见https://stackoverflow.com/a/39709740

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-20
      • 1970-01-01
      • 1970-01-01
      • 2016-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多