Wie blende ich ein UIVisualEffectView und / oder ein UIBlurEffect ein und aus?

92

Ich möchte eine UIVisualEffectsView mit einem UIBlurEffect ein- und ausblenden:

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

Ich verwende eine normale Animation innerhalb einer Funktion, die von a aufgerufen wird UIButton, um sie einzublenden. Gleiches gilt für das Ausblenden, aber .alpha = 0& hidden = true:

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

Nun, in beiden Richtungen Verblassen funktioniert , aber es gibt mir einen Fehler , wenn Schwund aus :

<UIVisualEffectView 0x7fdf5bcb6e80>wird gebeten, seine Opazität zu animieren. Dadurch wird der Effekt unterbrochen, bis die Deckkraft auf 1 zurückkehrt.

Frage

Wie kann ich das Ein- UIVisualEffectViewund Ausblenden erfolgreich einblenden , ohne es zu unterbrechen und einen verblassenden Übergang zu haben?

Hinweis

  • Ich habe versucht, das UIVisualEffectViewin ein zu setzen UIViewund dieses zu verblassen, kein Erfolg
LinusGeffarth
quelle
Sie können den Fehler vermeiden, indem Sie: 1. dem blurEffect KEINEN Anfangsstil zuweisen. dh var blurEffectView = UIVisualEffectView () und dann 2. Zuweisen des blurEffect zum blurEffectView INNERHALB des Animationsblocks. 3. Die Animation der "Zuweisung von blurEffect zu blurEffectView" erfolgt anstelle von Anpassungen an blurEffectView.alpha. ** Der Fehler wird auch dann angezeigt, wenn Sie einen Anfangswert zuweisen, ihn nicht angeben und dann wieder hinzufügen. Der Schlüssel zur Vermeidung des Fehlers besteht also darin, den Effekt erst im Animationsblock blurEffectView zuzuweisen.
ObjectiveTC
Außerdem muss erwähnt werden, dass blurEffectView alpha = 1.0 haben muss, um den Fehler zu vermeiden. Manipulationen an Alpha führen zu Fehlern. Wenn Sie beispielsweise vor dem Animationsblock blurEffectView.alpha = 0.7 festlegen und dann im animationBlock blurEffectView.effect = blurEffect zuweisen, wird der Fehler erzeugt.
ObjectiveTC

Antworten:

185

Ich denke, dies ist neu in iOS9, aber Sie können jetzt den Effekt eines UIVisualEffectViewinnerhalb eines Animationsblocks einstellen :

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

Stellen Sie es auf nilzu entfernen.

SEHR WICHTIG - Wenn Sie dies auf dem Simulator testen, stellen Sie sicher, dass die Überschreibung der Grafikqualität Ihres Simulators auf Hohe Qualität eingestellt ist, damit dies funktioniert.

jrturton
quelle
1
Funktioniert perfekt. Vielen Dank.
Baza207
Toll! Wie Sie sagten, funktioniert nicht für iOS 8: /
LinusGeffarth
Nun, genau wegen dem, was ich oben geschrieben habe. Ich habe es jetzt sowieso genehmigt. @jpros
LinusGeffarth
10
Sie können den Effekt auch auf Null setzen, um eine hübsche "Unschärfe" zu
erzielen
1
@jpros Würde es Ihnen etwas ausmachen zu erklären, was Sie unter "Unschärfe" verstehen?
Ndmeiri
19

In der Apple-Dokumentation heißt es (derzeit) ...

Vermeiden Sie bei Verwendung der UIVisualEffectView-Klasse Alpha-Werte, die kleiner als 1 sind.

und

Wenn Sie das Alpha in der visuellen Effektansicht oder einer der Übersichtsansichten auf weniger als 1 einstellen, sehen viele Effekte falsch aus oder werden überhaupt nicht angezeigt.

Ich glaube, hier fehlt ein wichtiger Kontext ...

Ich würde vorschlagen, dass die Absicht darin besteht, Alpha-Werte zu vermeiden, die für eine dauerhafte Ansicht kleiner als 1 sind. Meiner bescheidenen Meinung nach gilt dies nicht für die Animation einer Ansicht.

Mein Punkt - Ich würde vorschlagen, dass Alpha-Werte unter 1 für Animationen akzeptabel sind.

Die Terminalnachricht lautet:

UIVisualEffectView wird aufgefordert, seine Deckkraft zu animieren. Dadurch wird der Effekt unterbrochen, bis die Deckkraft auf 1 zurückkehrt.

Wenn Sie dies sorgfältig lesen, scheint der Effekt unterbrochen zu sein. Meine Punkte zu diesem Wesen:

  • Die offensichtliche Unterbrechung ist nur für eine Ansicht von Bedeutung, die hartnäckig ist - sich nicht ändert.
  • Eine dauerhafte / unveränderliche UIVisualEffectAnsicht mit einem Alpha-Wert von weniger als 1 wird nicht wie von Apple beabsichtigt / entworfen angezeigt. und
  • Die Nachricht im Terminal ist kein Fehler, sondern nur eine Warnung.

Um die Antwort von @ jrturton oben zu erweitern, die mir bei der Lösung meines Problems geholfen hat, würde ich hinzufügen ...

UIVisualEffectVerwenden Sie zum Ausblenden den folgenden Code (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()
} )

Ich verwende erfolgreich beide Methoden: Setzen der effectEigenschaft auf nilund Setzen der alphaEigenschaft auf 0.

Beachten Sie, dass durch Setzen von effectto nilam Ende der Animation ein "schöner Blitz" (aus Mangel an einer besseren Beschreibung) erzeugt wird , während durch Setzen von alphato 0ein reibungsloser Übergang erzeugt wird.

(Lassen Sie mich alle Syntaxfehler wissen ... Ich schreibe in obj-c.)

andrewbuilder
quelle
Vielen Dank für Ihren Beitrag. Ich verstehe was sie meinen; Der Fehler ist für mich bereits mit genau dem behoben, was Sie erwähnt haben :)
LinusGeffarth
14

Hier ist die Lösung, die ich gefunden habe und die sowohl auf iOS10 als auch auf früheren Versionen mit Swift 3 funktioniert

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

}

Sie können diese Übersicht auch überprüfen , um ein Beispiel für eine Verwendung zu finden.

Gunhan
quelle
Die Verwendung von UIViewPropertyAnimatorist das einzige, was in iOS 11 zu funktionieren scheint. Danke dafür!
LinusGeffarth
Vergessen Sie nicht hinzuzufügen: import UIKit
Oleksandr
8

Nur eine Problemumgehung - UIVisualEffectViewin eine Containeransicht einfügen und die alphaEigenschaft für diesen Container ändern . Dieser Ansatz funktioniert perfekt für mich unter iOS 9. Scheint unter iOS 10 nicht mehr zu funktionieren.

Beryllium
quelle
Cool. Danke, werde das versuchen :)
LinusGeffarth
1
Können Sie einen Beispielcode angeben? Das scheint nicht zu funktionieren.
cnotethegr8
Funktioniert für mich in iOS 9
5hrp
@DerrickHunt Gleich hier. Haben Sie eine Lösung gefunden?
Damirstuhec
2
@damirstuhec Wenn Ihr Projekt nur iOS 10 ist, können Sie die neue UIBlurView-Stärke mit der neuen UIViewPropertyAnimator-Klasse animieren. Wenn Sie ältere Versionen unterstützen müssen, können Sie den obigen Code und das Schlüsselwort #available verwenden, um UIViewPropertyAnimator für Geräte mit 10 zu verwenden. Ich hoffe, dies hilft!
Derrick Hunt
5

Sie können das Alpha der visuellen Effektansicht ohne Probleme ändern, abgesehen von der Warnung in der Konsole. Die Ansicht kann einfach als teilweise transparent und nicht als unscharf erscheinen. Dies ist jedoch normalerweise kein Problem, wenn Sie nur das Alpha während der Animation ändern.

Ihre App wird nicht abstürzen oder dafür abgelehnt. Testen Sie es auf einem realen Gerät (oder acht). Wenn Sie mit dem Aussehen und der Leistung zufrieden sind, ist es in Ordnung. Apple warnt Sie nur davor, dass es möglicherweise nicht so gut aussieht oder funktioniert wie eine visuelle Effektansicht mit einem Alpha-Wert von 1.

Dave Batton
quelle
5

Sie können einen Schnappschuss einer statischen zugrunde liegenden Ansicht erstellen und ein- und ausblenden, ohne die Deckkraft der Unschärfeansicht zu berühren. Angenommen, ein Ivar von 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()
    } )
}
David H.
quelle
Gute Idee auch, aber das funktioniert nicht gut für nicht statische (sich bewegende / animierende) Inhalte unterhalb der Unschärfeansicht.
LinusGeffarth
@LinusG. Nun, Apple sagt, man sollte nicht mit einer Alpha-Unschärfe-Ansicht herumspielen. Sie können einen CADisplayLink verwenden, um Screenshots Ihrer Basisansicht zu erstellen, diese dann in einer Bildansicht zu rendern (vielleicht eine, die Sie erstellt haben - sehr leicht) und diese in der Draufsicht anzuzeigen, während Sie die Deckkraft auf 0 ändern. Möglich, aber viele Arbeit.
David H.
1
Dies war (bisher) der einzige Weg, auf dem ich das erreichen konnte, was ich in iOS 10 wollte - ein Modal über Vollbild mit einem sehr dunklen Unschärfeeffekt einblenden. Vielen Dank!
Graham
3

Wenn Sie UIVisualEffectView einblenden möchten, verwenden Sie für 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]];
    }];

dann können Sie Prozent einstellen

[animator setFractionComplete:percent];

Für ios9 können Sie die Alpha-Komponente verwenden

kiril kiroski
quelle
2
Die Frage ist speziell mit "schnell" gekennzeichnet, nicht mit "Ziel-c": Bitte geben Sie eine Antwort in Swift. Vielen Dank!
Eric Aya
1
Vielen Dank für den Objective C Code. Ich fand es praktisch, da nicht viele andere Beispiele aufgeführt waren.
Adam Ware
2

Das Alpha von UIVisualEffectView muss immer 1 sein. Ich denke, Sie können den Effekt erzielen, indem Sie das Alpha der Hintergrundfarbe einstellen.

Quelle: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html

Peter Lendvay
quelle
Peter, kannst du bitte erklären, wie man das Alpha der Hintergrundfarbe einstellt?
Boris Y.
@borisy verwendet die colorWithAlphaComponent:Methode für die UIColorInstanzen. Ich bin mir jedoch nicht sicher, wie ich den gleichen Effekt beim Einstellen der Hintergrundfarbe erzielen kann.
Erzfeind
Durch Ändern des Hintergrunds Alpha-Komponente funktioniert nicht wie erwartet
Honghao Zhang
1

Ich mache eine Uiview, deren Alpha 0 ist, und füge Unschärfe als Unteransicht davon hinzu. So kann ich es mit Animation ausblenden / einblenden oder abrunden.

Kemal Can Kaynak
quelle
1

Am Ende hatte ich die folgende Lösung, bei der separate Animationen für den UIVisualEffectViewund den Inhalt verwendet wurden. Ich habe die viewWithTag()Methode verwendet, um einen Verweis auf das UIViewInnere des zu erhalten 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 }

Ich würde es vorziehen, wenn die einzelne Animation das Alpha ändert, aber dies vermeidet den Fehler und scheint genauso gut zu funktionieren.

demian
quelle
1

Ich hatte gerade dieses Problem und die Art und Weise, wie ich es umgehen konnte, bestand darin, die UIVisualEffectsView in einer UIView unterzubringen und das Alpha der UIView zu animieren.

Dies funktionierte gut, außer dass es, sobald sich das Alpha unter 1,0 änderte, zu einem festen Weiß wurde und sehr irritierend aussah. Um dies zu umgehen, müssen Sie die Layereigenschaft von UIView festlegen. Dadurch containerView.layer.allowsGroupOpacity = falsewird verhindert, dass sie weiß blinkt.

Jetzt können Sie die UIView mit der visuellen Effektansicht und allen anderen Unteransichten mithilfe ihrer Alpha-Eigenschaft animieren / ausblenden und müssen sich keine Gedanken über grafische Störungen machen oder eine Warnmeldung protokollieren.

user1898712
quelle
0
_visualEffectView.contentView.alpha = 0;

Um das Alpha von UIVisualEffectView zu ändern, sollten Sie die contentView von _visualEffectView ändern. Wenn Sie das Alpha von _visualEffectView ändern, erhalten Sie dies

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

Normalerweise möchte ich eine Unschärfe nur animieren, wenn ich einen Ansichts-Controller über dem Bildschirm präsentiere und den präsentierenden Ansichts-Controller verwischen möchte. Hier ist eine Erweiterung, die einem Ansichts-Controller blur () und unblur () hinzufügt, um dies zu vereinfachen:

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

Sie können dies natürlich robuster machen, indem Sie den Benutzer den Effektstil auswählen lassen, die Dauer ändern, nach Abschluss der Animation etwas aufrufen und die hinzugefügte visuelle Effektansicht in blur () markieren, um sicherzustellen, dass sie die einzige ist, die beim Aufheben der Unschärfe entfernt wird ( ) usw., aber ich habe bisher nicht die Notwendigkeit gefunden, diese Dinge zu tun, da dies in der Regel eine Art "Feuer und Vergessen" -Operation ist.

cc.
quelle
"Feuer und Vergessen" ist so zuordenbar! Ha
LinusGeffarth
0

Basierend auf der Antwort von @ cc habe ich seine Erweiterung geändert, um eine Ansicht zu verwischen

Erweiterung UIView {

    func blur () {
        // Verwische die aktuelle Ansicht
        let blurView = UIVisualEffectView (frame: self.bounds)
        self.addSubview (blurView)
        UIView.animate (withDuration: 0.25) {
            blurView.effect = UIBlurEffect (Stil: .dark)
        }}
    }}

    func unblur () {
        für childView in Unteransichten {
            Wache let effectView = childView als? UIVisualEffectView else {weiter}
            UIView.animate (withDuration: 2.5, Animationen: {
                effectView.effect = nil
            }) {
                didFinish in
                effectView.removeFromSuperview ()
            }}
        }}
    }}
}}
Tel4tel
quelle
0

Hier finden Sie eine Erweiterung mit Parametern und eine kurze Erklärung zur Verbesserung der @ Tel4tel- und @cc-Antwort.

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

Dann können Sie es verwenden wie: view.blur(duration: 5.0, effect: .light) oder view.unblur(duration: 3.0)

Denken Sie daran, es NICHT zu verwenden, viewDidLoad()da es die Animation überschreibt. Wenn Sie auf einem Simulator ausgeführt werden, drehen Sie die Grafiken auf die höhere Ebene, um die Animation anzuzeigen (Debug> Überschreiben der Grafikqualität> Hohe Qualität).

Rafael Díaz
quelle