Как вытеснить 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, не нарушая его и не имея переходного затухания?

Заметка

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

Ответ 1

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

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

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

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

Ответ 2

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

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

а также

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

Я считаю, что здесь не хватает важного контекста...

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

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

Терминальное сообщение гласит:

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

Читая это тщательно, эффект будет казаться сломан. Мои очки на это существо:

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

Ответ 3

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

}

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

Ответ 4

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

Ответ 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()
    } )
}

Ответ 6

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

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

Ответ 7

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

У меня просто была эта проблема, и способ, которым я обходился, состоял в том, чтобы разместить UIVisualEffectsView в UIView и анимировать UIView alpha.

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

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

Ответ 12

_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.

Ответ 13

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

Ответ 14

основываясь на ответе @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()
            }
        }
    }
}

Ответ 15

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