Як зникнути UIVisualEffectView та / або UIBlurEffect всередину та вийти?


92

Я хочу згладити 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 INSIDE блоку анімації. 3. анімація "присвоєння blurEffect blurEffectView" виконується замість коригувань blurEffectView.alpha. ** Помилка з'явиться, навіть якщо ви призначите початкове значення, відхилите його, а потім додасте назад. Отже, ключовим фактором запобігання помилки є не призначати ефект blurEffectView до блоку анімації.
ObjectiveTC

Також слід зазначити, що blurEffectView повинен мати альфа = 1,0, щоб уникнути помилки. Втручання в альфу будь-яким способом призведе до помилки. Наприклад, перед блоком анімації ви встановлюєте blurEffectView.alpha = 0,7, тоді в animationBlock ви призначаєте blurEffectView.effect = blurEffect, і виникає помилка.
ObjectiveTC

Відповіді:


185

Я думаю, що це нове в iOS9, але тепер ви можете встановити ефект UIVisualEffectViewвсередині анімаційного блоку:

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

Встановіть nilдля видалення.

ДУЖЕ ВАЖЛИВО - Випробовуючи це на тренажері, переконайтеся, що ви встановили для параметра «Якість графіки» симулятора значення «Висока якість», щоб це могло працювати.


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

14

Ось рішення, яке я знайшов, яке працює як на 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
            }
        }
    }

}

Ви також можете перевірити цю суть, щоб знайти приклад використання.


Використовуючи UIViewPropertyAnimatorце єдине , що , здається, працює в прошивці 11. Спасибі за це!
LinusGeffarth

Не забудьте додати: імпорт UIKit
Олександр

8

Просто обхідне рішення - розмістити UIVisualEffectViewу поданні контейнера та змінити alphaвластивість для цього контейнера. Цей підхід ідеально працює для мене на iOS 9. Здається, він більше не працює в iOS 10.


Класно. Дякую, спробую :)
LinusGeffarth

1
Чи можете ви надати зразок коду. Здається, це не працює.
cnotethegr8

Працює для мене в iOS 9
годин

@DerrickHunt Те саме тут. Ви знайшли рішення?
damirstuhec

2
@damirstuhec Якщо ваш проект призначений лише для iOS 10, ви можете використовувати новий клас UIViewPropertyAnimator для анімації сили UIBlurView. Якщо вам потрібна підтримка старих версій, ви можете використовувати наведений вище код та використовувати ключове слово #available для використання UIViewPropertyAnimator для пристроїв, що працюють на 10. Сподіваємось, це допоможе!
Деррік Хант

5

Ви можете змінити альфа-режим візуального ефекту без будь-яких проблем, крім попередження на консолі. Вигляд може виглядати просто частково прозорим, а не розмитим. Але це, як правило, не проблема, якщо ви просто змінюєте альфу під час анімації.

Ваш додаток не збирається виходити з ладу або отримувати відмову через це. Перевірте це на реальному пристрої (або восьми). Якщо ви задоволені тим, як це виглядає та працює, це чудово. Apple просто попереджає вас, що він може виглядати або працювати не так добре, як візуальні ефекти зі значенням альфа 1.


5

Ви можете зробити знімок статичного базового вигляду та згладити його всередину та назовні, не торкаючись прозорості розмитого вигляду. Припускаючи івар розмитості Перегляд:

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
Питання має теги "швидкий", а не "об'єктивний": будь ласка, надайте відповідь у "швидкому". Дякую!
Ерік Ая

1
Дякуємо за Кодекс Objective C. Я знайшов це зручним, оскільки не було багато інших прикладів.
Адам Варе

2

Альфа UIVisualEffectView завжди повинна бути 1. Я думаю, ви можете досягти ефекту, встановивши альфу кольору тла.

Джерело: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html


Пітере, ти можеш пояснити, як встановити альфа-колір фону?
Борис Ю.

@borisy використовують colorWithAlphaComponent:метод на UIColorекземплярах. Не знаю, як досягти того самого ефекту, встановивши колір фону.
Немезида

Зміна фонового альфа-компонента працює не так, як очікувалося
Хунхао Чжан,

1

Я роблю uiview, який альфа дорівнює 0, і додаю blurview як підпрогляд цього. Тож я можу приховати / показати або закруглити кути за допомогою анімації.


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, що містить перегляд візуальних ефектів та будь-які інші підпрограми, використовуючи його властивість альфа, і вам не доведеться турбуватися про будь-які графічні збої або реєстрацію попереджувального повідомлення.


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 (), щоб переконатися, що він єдиний видаляється при розмитті ( ) і т. д., але поки що я не знайшов потреби робити ці речі, оскільки це, як правило, тип операції "пожежа і забудь".


"вогонь і забудь" - це так просто! Ха
Лінус Геффарт

0

на основі відповіді @ cc я модифікував його розширення, щоб розмити погляд

розширення UIView {

    func blur () {
        // Розмити поточний вигляд
        нехай blurView = UIVisualEffectView (кадр: self.bounds)
        self.addSubview (blurView)
        UIView.animate (withDraration: 0,25) {
            blurView.effect = UIBlurEffect (стиль: .dark)
        }
    }

    func unblur () {
        для childView у підпрограмах {
            охорона нехай effectView = childView як? UIVisualEffectView else {продовжити}
            UIView.animate (withDuration: 2.5, анімація: {
                effectView.effect = нуль
            }) {
                закінчив в
                effectView.removeFromSuperview ()
            }
        }
    }
}

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()оскільки це замінить анімацію. Також під час роботи на симуляторі переведіть графіку на вищий рівень, щоб мати змогу бачити анімацію (Налагодження> Заміна якості графіки> Висока якість).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.