Представление контроллера представления с эффектом размытия

Я представляю View Controller модально с эффектом размытия фона. В iOS 10/XCode 8 появилась проблема с моей анимацией. Это код презентации:

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

Добавление размытия на функцию viewDidLoad() в ModalViewController:

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 с эффектом темного размытия. Пробовал как программно с предыдущим фрагментом, так и в Interface Builder.

В iOS 8 и 9 переход .CrossDissolve позаботился о «затухании», но после тестирования на iOS 10 (как на устройстве, так и на симуляторе) изображение появляется с темным полупрозрачным цветом фона вместо размытия.

После завершения анимации .CrossDissolve цвет фона меняется на фактический фон с эффектом размытия. Есть идеи, почему это происходит?

Также безуспешно пытался добавить layoutIfNeeded() в начале и конце viewDidLoad() для контроллера модального представления. Я использую свифт 2.3


person Fdo    schedule 22.09.2016    source источник
comment
Также обнаружили это раздражающее изменение в поведении. Вы пытались отключить стиль перехода и вручную обрабатывать анимацию?   -  person Johannes    schedule 26.09.2016
comment
Попробовал, выглядит лучше, но небольшая задержка по размытию все равно есть. Просто не так заметно   -  person Johannes    schedule 26.09.2016
comment
Для людей, которые забыли об этом, есть функция доступности, которая отключает размытие. Также +1 за ОП, у меня такая же проблема. У меня есть табличное представление с пользовательскими ячейками за представленным VC. Размытие применяется только к материалу позади в конце анимации перекрестного растворения, а затем внезапно размывает представляющий VC.   -  person cloudcal    schedule 04.01.2017


Ответы (3)


Hi,

Вам нужно создать новый файл UIViewControllerAnimatedTransitioning.

Затем в animateTransition(using transitionContext: UIViewControllerContextTransitioning) вам нужно закодировать вашу анимацию.

Теперь в iOS 10 вы можете использовать UIViewPropertyAnimator для анимации BlurRadius UIVisualBlurEffect.

Результат: введите здесь описание изображения

Вот пример использования: 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
    }

}
person Pierre Perrin    schedule 20.03.2017

Прежде всего, я рассматриваю это решение как временный обходной путь, потому что я должен предположить, что это новое поведение является ошибкой и будет исправлено в будущих обновлениях. Это делает его немного менее заметным, поскольку эффект размытия появляется во время анимации, а не после нее. Все еще не так хорошо, как в 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
        }
    }
    
person Johannes    schedule 26.09.2016
comment
Да, похоже, это единственный обходной путь на данный момент, хотя дополнительная задержка немного раздражает. Я оставлю вопрос открытым на некоторое время, прежде чем согласиться, надеясь, что кто-то может предложить альтернативное решение. - person Fdo; 26.09.2016
comment
Я понял вашу точку зрения, но вы можете изменить свой шаг 1 на presentViewController(modalVC, animated: false, completion: nil) - person Fdo; 26.09.2016
comment
Ой, спасибо @Fdo! Изменено animated на false. Я не надеялся, что этот ответ будет выбран в качестве решения, так как он далеко не безупречен. Также надеюсь, что кто-то придумает что-то лучше! - person Johannes; 26.09.2016

Единственный правильный способ — создать собственный модальный переход и анимировать свойство эффекта. См. https://stackoverflow.com/a/39709740.

person janmisar    schedule 12.10.2016