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

93

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

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и исчезать , что один, не успех
ЛинусГеффарт
источник
Вы можете избежать ошибки следующим образом: 1. НЕ назначать начальный стиль blurEffect. т.е. var blurEffectView = UIVisualEffectView (), а затем 2. назначение blurEffect на blurEffectView ВНУТРИ блока анимации. 3. Анимация «назначения blurEffect на blurEffectView» выполняется вместо настроек blurEffectView.alpha. ** Ошибка появится, даже если вы присвоите начальное значение, ноль, а затем добавите его обратно. Таким образом, ключ к предотвращению ошибки - не назначать эффект blurEffectView до блока анимации.
ObjectiveTC
Также необходимо упомянуть, что blurEffectView должен иметь alpha = 1.0, чтобы избежать ошибки. Любое вмешательство в альфа-канал приведет к ошибке. Например, перед блоком анимации вы устанавливаете blurEffectView.alpha = 0.7, затем в animationBlock вы назначаете blurEffectView.effect = blurEffect, возникает ошибка.
ObjectiveTC

Ответы:

187

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

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

Установите nilдля удаления.

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

Jrturton
источник
1
Прекрасно работает. Спасибо.
Baza207
Большой! Как вы сказали, не работает для iOS 8: /
LinusGeffarth
Ну именно из-за того, что я написал выше. Я все равно одобрил это сейчас. @jpros
LinusGeffarth
10
Вы также можете установить эффект на ноль, чтобы получить красивое «размытие»
jpros
1
@jpros Не могли бы вы объяснить, что вы имеете в виду под «размытием»?
ndmeiri
19

В документации 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.)

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

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

}

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

Gunhan
источник
Использование UIViewPropertyAnimator- единственное, что работает в iOS 11. Спасибо за это!
LinusGeffarth
Не забудьте добавить: import UIKit
Александр
8

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

бериллий
источник
Круто. Спасибо, попробую :)
LinusGeffarth 09
1
Можете ли вы предоставить образец кода. Похоже, это не работает.
cnotethegr8
У меня работает в iOS 9
5hrp
@DerrickHunt То же самое. Вы нашли решение?
damirstuhec
2
@damirstuhec Если ваш проект - только iOS 10, вы можете использовать новый класс UIViewPropertyAnimator для анимации силы UIBlurView. Если вам нужна поддержка более старых версий, вы можете использовать приведенный выше код и ключевое слово #available, чтобы использовать UIViewPropertyAnimator для устройств под управлением 10. Надеюсь, это поможет!
Деррик Хант
5

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

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

Дэйв Баттон
источник
5

Вы можете сделать снимок статического основного вида и затемнить его, не затрагивая прозрачность размытого вида. Предполагая 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()
    } )
}
Дэвид Х
источник
Хорошая идея, но она не будет работать для нестатического (движущегося / анимированного) контента под размытием.
LinusGeffarth,
@LinusG. Что ж, Apple говорит, что не стоит возиться с альфа-фильтром с размытым обзором. Вы можете использовать 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 вы можете использовать альфа-компонент

Кирил Кироски
источник
2
Вопрос специально помечен как «swift», а не «objective-c»: ответьте на Swift. Благодарность!
Эрик Айя,
1
Спасибо за код Objective C. Мне это показалось удобным, так как других примеров было немного.
Adam Ware
2

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

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

Питер Лендвей
источник
Питер, не могли бы вы объяснить, как установить альфа-канал цвета фона?
Борис Ю.
@borisy использует colorWithAlphaComponent:метод для UIColorэкземпляров. Однако не знаю, как добиться того же эффекта с помощью настройки цвета фона.
Немезида
При изменении фона альфа-компонент не работает
должным образом
1

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

Кемаль Джан Кайнак
источник
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 }

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

демиан
источник
1

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

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

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

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

cc.
источник
"выстрелил и забыл" так роднителен! Ха
LinusGeffarth
0

на основе ответа @cc я изменил его расширение, чтобы размыть представление

extension UIView {

    func blur () {
        // Размытие текущего вида
        let blurView = UIVisualEffectView (кадр: 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, анимации: {
                effectView.effect = ноль
            }) {
                сделал
                effectView.removeFromSuperview ()
            }
        }
    }
}
Tel4tel
источник
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()как он переопределит анимацию. Кроме того, при работе на симуляторе переключите графику на более высокий уровень, чтобы увидеть анимацию («Отладка»> «Переопределение качества графики»> «Высокое качество»).

Рафаэль Диас
источник