Как постепенно исчезать и исчезать UIVisualEffectView и / или UIBlurEffect?

Я хочу, чтобы UIVisualEffectsView исчезал с помощью UIBlurEffect:

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
}

Теперь затухание в обоих направлениях работает, но при исчезновении выдает сообщение об ошибке:

<UIVisualEffectView 0x7fdf5bcb6e80> просят оживить его непрозрачность. Это приведет к тому, что эффект будет казаться нарушенным, пока непрозрачность не вернется к 1.

Вопрос

Как мне успешно увеличивать и уменьшать UIVisualEffectView, не нарушая его и не имея переходного затухания?

Примечание

  • Я пытался вставить UIVisualEffectView в UIView и затемнить его, безуспешно

person LinusGeffarth    schedule 27.03.2015    source источник
comment
Вы можете избежать ошибки следующим образом: 1. НЕ назначать начальный стиль blurEffect. т.е. var blurEffectView = UIVisualEffectView (), а затем 2. присвоение blurEffect параметру blurEffectView ВНУТРИ блока анимации. 3. Анимация назначения blurEffect на blurEffectView выполняется вместо настроек blurEffectView.alpha. ** Ошибка появится, даже если вы присвоите начальное значение, ноль, а затем добавите его обратно. Таким образом, ключ к предотвращению ошибки - не назначать эффект blurEffectView до блока анимации.   -  person ObjectiveTC    schedule 11.11.2015
comment
Также необходимо упомянуть, что blurEffectView должен иметь значение alpha = 1.0, чтобы избежать ошибки. Любое вмешательство в альфа-канал приведет к ошибке. Например, перед блоком анимации вы устанавливаете blurEffectView.alpha = 0.7, затем в animationBlock вы назначаете blurEffectView.effect = blurEffect, возникает ошибка.   -  person ObjectiveTC    schedule 11.11.2015


Ответы (15)


Я думаю, что это новое в iOS9, но теперь вы можете установить эффект UIVisualEffectView внутри блока анимации:

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

Установите nil, чтобы удалить.

ОЧЕНЬ ВАЖНО. При тестировании этого на симуляторе убедитесь, что для параметра «Переопределение качества графики» симулятора установлено значение «Высокое качество», чтобы это работало.

person jrturton    schedule 25.09.2015
comment
Прекрасно работает. Спасибо. - person Baza207; 13.10.2015
comment
Большой! Как вы сказали, для iOS 8 не работает: / - person LinusGeffarth; 11.11.2015
comment
Ну именно из-за того, что я написал выше. Я все равно одобрил это сейчас. @jpros - person LinusGeffarth; 13.11.2015
comment
Вы также можете установить эффект на ноль, чтобы получить довольно размытое размытие. - person jpros; 14.11.2015
comment
@jpros Не могли бы вы объяснить, что вы имеете в виду под размытием? - person ndmeiri; 27.03.2016
comment
Любая идея, как не анимировать его, а установить как 50% эффекта? - person Georg; 24.11.2016
comment
Это не работает. Когда вы играете с большим вниманием, вы видите, что эффект размытия добавляется только в конце анимации. UIBlurEffect не может быть анимирован в iOS10.3. См. Ответ andrewbuilder ниже. - person Manuel; 08.09.2017
comment
@ Мануэль, это работает. Вы делаете это на тренажере или устройстве (на тренажере это выглядит ужасно) - person jrturton; 08.09.2017
comment
@jrturton на устройстве. Я добавляю UIVisualEffectsView в представление на viewDidLoad и добавляю свойство effect на viewWillAppear. Я вижу, как анимация затемняет фон до финального оттенка, затем мгновенно добавляется размытие. - person Manuel; 08.09.2017
comment
Тогда я не уверен, что происходит. Я работаю над другими проектами. Вероятно, лучше всего задать новый вопрос и указать вашу конкретную настройку. - person jrturton; 09.09.2017
comment
@VyachaslavGerchicov Красиво работает. По сути, вы помещаете в представление пустой UIVisualEffectView и анимируете эффект, поэтому вы устанавливаете эффект внутри блока анимации. - person Adrian; 18.03.2018

В документации Apple (в настоящее время) говорится. ..

При использовании класса UIVisualEffectView избегайте альфа-значений меньше 1.

а также

Установка альфа меньше 1 в представлении визуальных эффектов или любом из его супервизоров приводит к тому, что многие эффекты выглядят некорректно или вообще не отображаются.

Я считаю, что здесь отсутствует какой-то важный контекст ...

Я бы предположил, что цель состоит в том, чтобы избежать значений альфа, которые меньше 1 для постоянного представления. По моему скромному мнению, это не относится к анимации вида.

Моя точка зрения - я бы предположил, что для анимации приемлемы альфа-значения менее 1.

В терминальном сообщении говорится:

UIVisualEffectView просят анимировать его непрозрачность. Это приведет к тому, что эффект будет казаться нарушенным, пока непрозрачность не вернется к 1.

Если внимательно прочитать это, эффект появится будет нарушен. Мои соображения по этому поводу:

  • кажущийся разрыв действительно имеет значение только для стойкого взгляда, а не для изменения;
  • постоянное / неизменное UIVisualEffect представление с альфа-значением меньше 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.

Обратите внимание, что установка effect на nil создает "красивую вспышку" (из-за отсутствия лучшего описания) в конце анимации, а установка alpha на 0 создает плавный переход.

(Сообщите мне о любых синтаксических ошибках ... Я пишу в obj-c.)

person andrewbuilder    schedule 26.03.2016
comment
Спасибо за ваш вклад. Я понимаю вашу точку зрения; ошибка решена для меня уже с тем, что вы упомянули :) - person LinusGeffarth; 26.03.2016

Вот решение, которое я нашел, которое работает как на 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
            }
        }
    }

}

Вы также можете проверить эту суть, чтобы найти пример использования.

person Gunhan    schedule 16.02.2017
comment
Использование UIViewPropertyAnimator - единственное, что работает в iOS 11. Спасибо за это! - person LinusGeffarth; 29.09.2017
comment
Не забудьте добавить: import UIKit - person J A S K I E R; 19.03.2020

Просто обходной путь - поместите UIVisualEffectView в представление контейнера и измените свойство alpha для этого контейнера. Этот подход отлично работает у меня на iOS 9. Кажется, он больше не работает в iOS 10.

person beryllium    schedule 09.07.2015
comment
Прохладный. Спасибо, попробую :) - person LinusGeffarth; 09.07.2015
comment
Можете ли вы предоставить образец кода. Похоже, это не работает. - person cnotethegr8; 10.11.2015
comment
У меня работает в iOS 9 - person 5hrp; 27.05.2016
comment
@DerrickHunt То же самое. Вы нашли решение? - person damirstuhec; 27.09.2016
comment
@damirstuhec Если ваш проект работает только с iOS 10, вы можете использовать новый класс UIViewPropertyAnimator для анимации силы UIBlurView. Если вам нужна поддержка более старых версий, вы можете использовать приведенный выше код и ключевое слово #available, чтобы использовать UIViewPropertyAnimator для устройств под управлением 10. Надеюсь, это поможет! - person Derrick Hunt; 28.09.2016
comment
@DerrickHunt Любая идея, как не анимировать его, а настроить на 50% эффекта? - person Georg; 24.11.2016
comment
@Georg iOS 10 или ниже? - person Derrick Hunt; 05.12.2016
comment
iOS10 ... на ‹iOS он работал, изменяя альфа-канал представления контейнера ... но теперь на iOS10 мое интерактивное размытие нарушено :( - person Georg; 06.12.2016

Вы можете изменить альфа-канал представления визуальных эффектов без каких-либо проблем, кроме предупреждения в консоли. Вид может выглядеть просто частично прозрачным, а не размытым. Но обычно это не проблема, если вы просто меняете альфа во время анимации.

Ваше приложение не выйдет из строя или будет отклонено из-за этого. Протестируйте на реальном устройстве (или восьмерке). Если вам нравится, как он выглядит и работает, ничего страшного. Apple просто предупреждает вас, что он может не выглядеть или работать так же хорошо, как представление визуальных эффектов с альфа-значением 1.

person Dave Batton    schedule 13.05.2015

Вы можете сделать снимок статического основного вида и затемнить его, не затрагивая непрозрачность размытого вида. Предполагая ivar для 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()
    } )
}
person David H    schedule 29.07.2015
comment
Хорошая идея, но она не будет работать для нестатического (движущегося / анимированного) контента под размытием. - person LinusGeffarth; 29.07.2015
comment
@LinusG. Что ж, Apple говорит, что не стоит возиться с альфа-фильтром с размытым обзором. Вы можете использовать CADisplayLink для захвата снимков экрана вашего базового вида, затем визуализировать их в виде изображения (возможно, такое, которое вы сделали - очень легкое) - и отображать их на виде сверху, изменяя его непрозрачность на 0. Возможно, но много. Работа. - person David H; 29.07.2015
comment
Это был единственный способ (пока) мне удалось добиться того, чего я хотел в iOS 10, - постепенного перехода в полноэкранный режим с очень темным эффектом размытия. Спасибо! - person Graham; 06.02.2017

Если вы хотите исчезнуть в 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 вы можете использовать альфа-компонент

person kiril kiroski    schedule 07.12.2016
comment
Вопрос специально помечен как быстрый, а не объективный-c: пожалуйста, дайте ответ на Swift. Спасибо! - person Eric Aya; 07.12.2016
comment
Спасибо за код Objective C. Мне это показалось удобным, так как других примеров было не так много. - person Adam Ware; 24.03.2018

Альфа UIVisualEffectView всегда должна быть 1. Я думаю, вы можете добиться эффекта, установив альфа цвета фона.

Источник: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html

person Peter Lendvay    schedule 27.03.2015
comment
Питер, не могли бы вы объяснить, как установить альфа-канал цвета фона? - person Boris Y.; 14.04.2015
comment
@borisy использует метод colorWithAlphaComponent: на экземплярах UIColor. Однако не знаю, как добиться того же эффекта, задав цвет фона. - person nemesis; 15.05.2015
comment
При изменении фона альфа-компонент не работает должным образом - person Honghao Zhang; 13.11.2015

Я делаю uiview, альфа которого равна 0, и добавляю размытие в качестве subview этого. Так что я могу скрыть / показать или закруглить углы с помощью анимации.

person Kemal Can Kaynak    schedule 02.12.2015

Я пришел к следующему решению, используя отдельные анимации для 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 }

Я бы предпочел одиночную анимацию, меняющую альфу, но это позволяет избежать ошибки и, похоже, работает так же хорошо.

person demian    schedule 06.11.2015

У меня только что возникла эта проблема, и я решил ее обойти: разместить UIVisualEffectsView в UIView и оживить альфа-канал UIView.

Это сработало хорошо, за исключением того, что как только альфа изменилась ниже 1.0, она превратилась в сплошной белый цвет и выглядела очень неприятно. Чтобы обойти это, вы должны установить свойство слоя UIView containerView.layer.allowsGroupOpacity = false, и это предотвратит мигание белого цвета.

Теперь вы можете анимировать / затухать UIView, содержащий представление визуальных эффектов и любые другие подпредставления, используя его свойство alpha, и вам не нужно беспокоиться о каких-либо графических сбоях или регистрации предупреждающего сообщения.

person user1898712    schedule 13.06.2017

_visualEffectView.contentView.alpha = 0;

Чтобы изменить альфа-канал UIVisualEffectView, вы должны изменить contentView для _visualEffectView. Если вы измените альфа-канал для _visualEffectView, вы получите следующее

<UIVisualEffectView 0x7ff7bb54b490> is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.
person chile    schedule 29.03.2016

Обычно я хочу анимировать размытие только тогда, когда я представляю контроллер представления над экраном и хочу размыть представляющий контроллер представления. Вот расширение, которое добавляет 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 (), чтобы убедиться, что он единственный удаляется, когда вы снимаете размытие ( ) и т. д., но я пока не обнаружил в этом необходимости, поскольку это, как правило, операция типа «выстрелил и забыл».

person cc.    schedule 30.05.2017
comment
огонь и забыть так роднителен! Ха - person LinusGeffarth; 30.05.2017

на основе ответа @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()
            }
        }
    }
}
person Tel4tel    schedule 30.08.2018

Улучшение ответа @ 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(), так как он переопределит анимацию. Кроме того, при работе на симуляторе переключите графику на более высокий уровень, чтобы увидеть анимацию («Отладка»> «Переопределение качества графики»> «Высокое качество»).

person Rafael Díaz    schedule 13.09.2018