Jak włączać i wyłączać UIVisualEffectView i / lub UIBlurEffect?


93

Chcę zanikać UIVisualEffectsView za pomocą UIBlurEffect in and out:

var blurEffectView = UIVisualEffectView()
blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))

Używam normalnej animacji w funkcji wywoływanej przez a, UIButtonaby ją wprowadzić, tak samo jak przy zanikaniu, ale .alpha = 0& hidden = true:

blurEffectView.hidden = false
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut) {
    self.blurEffectView.alpha = 1
}

Teraz blaknięcie w obu kierunkach działa, ale daje mi błąd podczas blaknięcie się :

<UIVisualEffectView 0x7fdf5bcb6e80>jest proszony o animację jego krycia. Spowoduje to, że efekt będzie wyglądał na uszkodzony, dopóki krycie nie powróci do 1.

Pytanie

Jak z powodzeniem wprowadzać UIVisualEffectViewi wyłączać wejście bez przerywania go i zanikania przejścia?

Uwaga

  • Próbowałem wstawić UIVisualEffectViewa UIViewi zniknąć, bez powodzenia

Możesz uniknąć Błędu poprzez: 1. NIE przypisywanie początkowego stylu efektowi blurEffect. tj. var blurEffectView = UIVisualEffectView (), a następnie 2. przypisanie efektu blurEffect do bloku blurEffectView WEWNĄTRZ bloku animacji. 3. Animowanie „przypisania blurEffect do blurEffectView” odbywa się w miejsce zmian w blurEffectView.alpha. ** Błąd pojawi się, nawet jeśli przypiszesz wartość początkową, zeruj ją, a następnie dodaj ją z powrotem. Dlatego kluczem do uniknięcia błędu jest nie przypisanie efektu do blurEffectView aż do bloku animacji.
ObjectiveTC

Należy również wspomnieć, że blurEffectView musi mieć wartość alpha = 1.0, aby uniknąć błędu. Jakakolwiek ingerencja w alfę spowoduje błąd. Np. Przed blokiem animacji ustawiasz blurEffectView.alpha = 0.7, a następnie w animacjiBlock przypisujesz blurEffectView.effect = blurEffect, błąd jest generowany.
ObjectiveTC

Odpowiedzi:


187

Myślę, że to nowość w iOS9, ale możesz teraz ustawić efekt UIVisualEffectViewwewnątrz bloku animacji:

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

Ustaw go, nilaby usunąć.

BARDZO WAŻNE - Podczas testowania tego na symulatorze, upewnij się, że ustawiłeś nadpisanie jakości grafiki w symulatorze na wysoką jakość, aby to zadziałało.


1
Działa świetnie. Dzięki.
Baza207

Świetny! Jak powiedziałeś, nie działa jednak na iOS 8: /
LinusGeffarth

No właśnie z powodu tego, co napisałem powyżej. I tak to teraz zaakceptowałem. @jpros
LinusGeffarth

10
Możesz też ustawić efekt na zero, aby uzyskać ładne „rozmycie”
jpros

1
@jpros Czy mógłbyś wyjaśnić, co masz na myśli, mówiąc „rozmazać się”?
ndmeiri

19

Dokumentacja Apple (obecnie) stwierdza ...

Korzystając z klasy UIVisualEffectView, unikaj wartości alfa, które są mniejsze niż 1.

i

Ustawienie alfa na mniej niż 1 w widoku efektu wizualnego lub w którymkolwiek z jego podglądów nadzoru powoduje, że wiele efektów wygląda nieprawidłowo lub w ogóle się nie pojawia.

Uważam, że brakuje tu jakiegoś ważnego kontekstu ...

Sugerowałbym, aby celem było unikanie wartości alfa, które są mniejsze niż 1 dla trwałego widoku. Moim skromnym zdaniem nie dotyczy to animacji widoku.

Moja uwaga - sugerowałbym, że wartości alfa mniejsze niż 1 są dopuszczalne dla animacji.

Komunikat terminala stwierdza:

UIVisualEffectView jest proszony o animowanie jego krycia. Spowoduje to, że efekt będzie wyglądał na uszkodzony, dopóki krycie nie powróci do 1.

Czytając to uważnie, efekt wydaje się zepsuty. Moje uwagi na ten temat:

  • pozorna przerwa ma znaczenie tylko w przypadku poglądu, który jest trwały - nie zmienia się;
  • trwały / niezmienny UIVisualEffect widok z wartością alfa mniejszą niż 1 nie będzie się prezentował zgodnie z zamierzeniami / projektami Apple; i
  • komunikat w terminalu nie jest błędem, tylko ostrzeżeniem.

Aby rozszerzyć powyższą odpowiedź @ jrturton, która pomogła mi rozwiązać problem, dodam ...

Aby zaniknąć UIVisualEffectużyj następującego kodu (celu-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()
} )

Z powodzeniem używam obu metod: ustawiając effectwłaściwość na nili ustawiając alphawłaściwość na 0.

Należy pamiętać, że ustawienie effectsię niltworzy „piękny błysk” (z braku lepszego opisu) na końcu animacji, natomiast ustawienie alphana 0tworzy płynne przejście.

(Daj mi znać o wszelkich błędach składniowych ... Piszę w obj-c.)


Dziękuję za Twój wkład. Wiem o co ci chodzi; błąd został już rozwiązany dla mnie z dokładnie tym, o czym wspomniałeś :)
LinusGeffarth

15

Oto rozwiązanie, które skończyłem, które działa zarówno na iOS10, jak i wcześniejszych wersjach przy użyciu 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
            }
        }
    }

}

Możesz również sprawdzić tę treść, aby znaleźć przykładowe użycie.


UIViewPropertyAnimatorWydaje się, że jedyną rzeczą, która działa w iOS 11, jest używanie programu . Dzięki za to!
LinusGeffarth

Nie zapomnij dodać: import UIKit
Oleksandr

8

Tylko obejście - umieść UIVisualEffectVieww widoku kontenera i zmień alphawłaściwość dla tego kontenera. To podejście działa idealnie dla mnie na iOS 9. Wygląda na to, że nie działa już w iOS 10.


Fajne. Dzięki, spróbuję :)
LinusGeffarth

1
Czy możesz podać przykładowy kod. To nie wydaje się działać.
cnotethegr8

Działa dla mnie w iOS 9
5hrp

@DerrickHunt To samo tutaj. Znalazłeś rozwiązanie?
damirstuhec

2
@damirstuhec Jeśli Twój projekt dotyczy tylko systemu iOS 10, możesz użyć nowej klasy UIViewPropertyAnimator do animowania siły UIBlurView. Jeśli potrzebujesz obsługi starszych wersji, możesz użyć powyższego kodu i słowa kluczowego #available, aby użyć UIViewPropertyAnimator dla urządzeń z systemem 10. Mam nadzieję, że to pomoże!
Derrick Hunt

5

Możesz bez problemu zmienić alfa widoku efektów wizualnych poza ostrzeżeniem w konsoli. Widok może wydawać się po prostu częściowo przezroczysty, a nie zamazany. Ale zwykle nie stanowi to problemu, jeśli zmieniasz alfa podczas animacji.

Twoja aplikacja nie ulegnie awarii ani nie zostanie z tego powodu odrzucona. Przetestuj na prawdziwym urządzeniu (lub ośmiu). Jeśli jesteś zadowolony z tego, jak wygląda i działa, jest w porządku. Apple ostrzega tylko, że może nie wyglądać lub działać tak dobrze, jak widok efektów wizualnych z wartością alfa 1.


5

Możesz zrobić migawkę statycznego widoku znajdującego się pod spodem i zanikać go bez dotykania krycia widoku rozmycia. Zakładając blask 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()
    } )
}

Niezły pomysł, ale nie będzie dobrze działać w przypadku niestatycznych (ruchomych / animowanych) treści pod widokiem rozmycia.
LinusGeffarth

@LinusG. Cóż, Apple twierdzi, że nie powinno się bawić z rozmytym widokiem alfa. Możesz użyć CADisplayLink, aby pobrać zrzuty ekranu widoku podstawowego, a następnie wyrenderować je w widoku obrazu (być może takim, który zrobiłeś - naprawdę lekki) - i pokazać je w widoku z góry, zmieniając krycie na 0. Możliwe, ale dużo praca.
David H

1
To był jedyny sposób, w jaki (jak dotąd) udało mi się osiągnąć to, co chciałem w iOS 10 - zanikać modalnie na pełnym ekranie, z efektem bardzo ciemnego rozmycia. Dzięki!
Graham

3

Jeśli chcesz zaniknąć w Tobie UIVisualEffectView - dla iOS10 użyj 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]];
    }];

wtedy możesz ustawić procent

[animator setFractionComplete:percent];

dla ios9 możesz użyć komponentu alfa


2
Pytanie jest konkretnie oznaczone jako „szybki”, a nie „obiektyw-c”: podaj odpowiedź w języku Swift. Dzięki!
Eric Aya

1
Dzięki za kod Objective C. Wydało mi się to przydatne, ponieważ nie wymieniono wielu innych przykładów.
Adam Ware

2

Alfa UIVisualEffectView zawsze musi wynosić 1. Myślę, że można osiągnąć ten efekt, ustawiając alfa koloru tła.

Źródło: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html


Peter, czy możesz wyjaśnić, jak ustawić alfa koloru tła?
Boris Y.

@borisy użyj colorWithAlphaComponent:metody w UIColorinstancjach. Nie wiem jednak, jak osiągnąć ten sam efekt, ustawiając kolor tła.
nemesis

Zmieniając tło, składnik alfa nie działa zgodnie z oczekiwaniami
Honghao Zhang

1

Robię uiview, którego alfa wynosi 0 i dodaję blurview jako subview tego. Więc mogę ukryć / pokazać lub zaokrąglić rogi za pomocą animacji.


1

Skończyło się na następującym rozwiązaniu, używając osobnych animacji dla UIVisualEffectViewtreści i. Użyłem tej viewWithTag()metody, aby uzyskać odniesienie do UIViewwnętrza 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 }

Wolałbym pojedynczą animację zmieniającą alfa, ale to pozwala uniknąć błędu i wydaje się działać równie dobrze.


1

Właśnie miałem ten problem i sposób, w jaki go obejść, polegał na umieszczeniu UIVisualEffectsView w UIView i animacji alfa UIView.

To działało dobrze, z wyjątkiem tego, że gdy tylko wartość alfa zmieniła się poniżej 1,0, zmieniła się w jednolitą biel i wyglądała bardzo drażniąco. Aby to obejść, musisz ustawić właściwość warstwy UIView, containerView.layer.allowsGroupOpacity = falseco zapobiegnie miganiu na biało.

Teraz możesz animować / zanikać UIView zawierający widok efektów wizualnych i wszelkie inne podwidoki przy użyciu jego właściwości alfa i nie musisz się martwić o żadne błędy graficzne lub rejestrowanie komunikatu ostrzegawczego.


0
_visualEffectView.contentView.alpha = 0;

Aby zmienić alfa UIVisualEffectView, należy zmienić contentView w _visualEffectView. Jeśli zmienisz alfa w _visualEffectView, otrzymasz to

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

0

Zwykle chcę animować rozmycie tylko wtedy, gdy przedstawiam kontroler widoku na ekranie i chcę rozmazać kontroler widoku prezentacji. Oto rozszerzenie, które dodaje blur () i unblur () do kontrolera widoku, aby to ułatwić:

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()
           }
       }
   }
}

Możesz oczywiście uczynić to bardziej solidnym, pozwalając użytkownikowi wybrać styl efektu, zmodyfikować czas trwania, wywołać coś po zakończeniu animacji, oznaczyć dodany widok efektu wizualnego w rozmyciu (), aby upewnić się, że jest to jedyny usuwany po odblokowaniu ( ) itp., ale jak dotąd nie znalazłem potrzeby robienia tych rzeczy, ponieważ jest to zwykle operacja typu „odpal i zapomnij”.


„Odpal i zapomnij” jest bardzo zrozumiałe! Ha
LinusGeffarth

0

na podstawie odpowiedzi @ cc zmodyfikowałem jego rozszerzenie, aby zamazać widok

rozszerzenie UIView {

    func blur () {
        // Rozmyj bieżący widok
        let blurView = UIVisualEffectView (ramka: self.bounds)
        self.addSubview (blurView)
        UIView.animate (withDuration: 0,25) {
            blurView.effect = UIBlurEffect (styl: .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 ()
            }
        }
    }
}

0

Poprawiając odpowiedź @ Tel4tel i @cc, oto rozszerzenie z parametrami i krótkim wyjaśnieniem.

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()
            }
        }
    }
}

Następnie możesz go użyć w ten sposób: view.blur(duration: 5.0, effect: .light) lub view.unblur(duration: 3.0)

Pamiętaj, aby NIE używać go w, viewDidLoad()ponieważ nadpisuje animację. Ponadto, podczas uruchamiania w symulatorze, przełącz grafikę na wyższy poziom, aby móc zobaczyć animację (Debugowanie> Nadpisanie jakości grafiki> Wysoka jakość).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.