Ein einfaches Einblenden der Animation in Swift?


80

Ich versuche eine einfache Animation in Swift zu erstellen. Es ist ein Einblenden.

Ich versuchte:

self.myFirstLabel.alpha = 0
self.myFirstButton.alpha = 0
self.mySecondButton.alpha = 0

Dann habe ich:

self.view.addSubview(myFirstLabel)
self.view.addSubview(myFirstButton)
self.view.addSubview(mySecondButton)

Und dann:

UIView.animateWithDuration(1.5, animations: {
 self.myFirstLabel.alpha = 1.0
 self.myFirstButton.alpha = 1.0
 self.mySecondButton.alpha = 1.0
})

Ich habe all dies in meiner viewDidLoad-Funktion.

Wie mache ich das?


Alle Elemente kommen gleichzeitig herein. Genau dann, wenn die Ansicht geladen wird.
Benr783

Sind Sie sicher, dass die Ansichten in der xib richtig angeschlossen sind?
Drawag

Ich benutze kein IB. Alles ist programmatisch.
Benr783

Nach dem von Ihnen angegebenen Code sollte alles funktionieren (und das hat nichts mit Swift zu tun). An anderer Stelle muss ein Fehler vorliegen.
Drawag

Verschieben Sie den Aufruf der Ansichtsansicht für Ansichten in viewWillAppearoder viewDidAppearweil Sie nicht wissen, was zwischen dem Laden und Anzeigen der Ansicht passiert.
A-Live

Antworten:


119

Das Problem ist, dass Sie versuchen, die Animation zu früh im Lebenszyklus des View Controllers zu starten. In viewDidLoadwurde die Ansicht gerade erstellt und noch nicht zur Ansichtshierarchie hinzugefügt. Der Versuch, eine subviewsdieser Ansichten zu animieren, führt daher zu schlechten Ergebnissen.

Was Sie wirklich tun sollten, ist weiterhin das Alpha der Ansicht festzulegen viewDidLoad(oder wo Sie Ihre Ansichten erstellen) und dann auf den viewDidAppearAufruf der Methode: zu warten . An diesem Punkt können Sie Ihre Animationen ohne Probleme starten.

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    UIView.animate(withDuration: 1.5) {
        self.myFirstLabel.alpha = 1.0
        self.myFirstButton.alpha = 1.0
        self.mySecondButton.alpha = 1.0
    }
}

Ist das viewWillAppearbesser geeignet?
Tonne

1
Denken Sie daran, wenn Sie nur 1 Anweisung haben, müssen Sie eine Rückgabe hinzufügenUIView.animateWithDuration(1.5, animations: { self.myFirstLabel.alpha = 1.0 return })
Oshevans

@oshevans Beziehen Sie sich auf die Notwendigkeit, am Ende des Abschlusses eine Rückgabeerklärung hinzuzufügen? Dies wurde größtenteils in den neuesten Xcode-Versionen behoben.
Mick MacCallum

Ich habe einen sehr ähnlichen Fehler. Bitte sehen Sie, ob Sie mir helfen können: stackoverflow.com/questions/29910669/…
Teo Inke

@ 0x7fffffff '... meistens behoben ...' - das klingt nicht vielversprechend; / Noch von 6.2 zu aktualisieren
Oshevans

46

Die Antwort von 0x7ffffff ist in Ordnung und definitiv erschöpfend.

Als Plus empfehle ich Ihnen, eine UIView-Erweiterung auf folgende Weise zu erstellen:

public extension UIView {

  /**
  Fade in a view with a duration

  - parameter duration: custom animation duration
  */
  func fadeIn(duration duration: NSTimeInterval = 1.0) {
    UIView.animateWithDuration(duration, animations: {
        self.alpha = 1.0
    })
  }

  /**
  Fade out a view with a duration

  - parameter duration: custom animation duration
  */
  func fadeOut(duration duration: NSTimeInterval = 1.0) {
    UIView.animateWithDuration(duration, animations: {
        self.alpha = 0.0
    })
  }

}

Swift-3

/// Fade in a view with a duration
/// 
/// Parameter duration: custom animation duration
func fadeIn(withDuration duration: TimeInterval = 1.0) {
    UIView.animate(withDuration: duration, animations: {
        self.alpha = 1.0
    })
}

/// Fade out a view with a duration
///
/// - Parameter duration: custom animation duration
func fadeOut(withDuration duration: TimeInterval = 1.0) {
    UIView.animate(withDuration: duration, animations: {
        self.alpha = 0.0
    })
}

Auf diese Weise können Sie dies überall in Ihrem Code tun:

let newImage = UIImage(named: "")
newImage.alpha = 0 // or newImage.fadeOut(duration: 0.0)
self.view.addSubview(newImage)
... 
newImage.fadeIn()

Die Wiederverwendung von Code ist wichtig!


7

Schnelle Lösung

Ähnlich wie bei Lucas Antwort verwende ich eine UIViewErweiterung. Im Vergleich zu seiner Lösung DispatchQueue.main.asyncstelle ich sicher, dass Animationen im Hauptthread ausgeführt werden, alphaParameter zum Überblenden auf einen bestimmten Wert und optionale durationParameter für saubereren Code.

extension UIView {
  func fadeTo(_ alpha: CGFloat, duration: TimeInterval = 0.3) {
    DispatchQueue.main.async {
      UIView.animate(withDuration: duration) {
        self.alpha = alpha
      }
    }
  }

  func fadeIn(_ duration: TimeInterval = 0.3) {
    fadeTo(1.0, duration: duration)
  }

  func fadeOut(_ duration: TimeInterval = 0.3) {
    fadeTo(0.0, duration: duration)
  }
}

Wie man es benutzt:

// fadeIn() - always animates to alpha = 1.0
yourView.fadeIn()     // uses default duration of 0.3
yourView.fadeIn(1.0)  // uses custom duration (1.0 in this example)

// fadeOut() - always animates to alpha = 0.0
yourView.fadeOut()    // uses default duration of 0.3
yourView.fadeOut(1.0) // uses custom duration (1.0 in this example)

// fadeTo() - used if you want a custom alpha value
yourView.fadeTo(0.5)  // uses default duration of 0.3
yourView.fadeTo(0.5, duration: 1.0)

5

Wenn Sie wiederholbare Überblendungsanimationen wünschen, können Sie dies CABasicAnimationwie folgt tun :

Erstellen Sie zuerst eine praktische UIView-Erweiterung:

extension UIView {

    enum AnimationKeyPath: String {
        case opacity = "opacity"
    }

    func flash(animation: AnimationKeyPath ,withDuration duration: TimeInterval = 0.5, repeatCount: Float = 5){
        let flash = CABasicAnimation(keyPath: animation.rawValue)
        flash.duration = duration
        flash.fromValue = 1 // alpha
        flash.toValue = 0 // alpha
        flash.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        flash.autoreverses = true
        flash.repeatCount = repeatCount

        layer.add(flash, forKey: nil)
    }
}

Wie man es benutzt:

    // You can use it with all kind of UIViews e.g. UIButton, UILabel, UIImage, UIImageView, ...
    imageView.flash(animation: .opacity, withDuration: 1, repeatCount: 5)
    titleLabel.flash(animation: .opacity, withDuration: 1, repeatCount: 5)

0
import UIKit

/*
 Here is simple subclass for CAAnimation which create a fadeIn animation
 */

class FadeInAdnimation: CABasicAnimation {
    override init() {
        super.init()
        keyPath = "opacity"
        duration = 2.0
        fromValue = 0
        toValue = 1
        fillMode = CAMediaTimingFillMode.forwards
        isRemovedOnCompletion = false
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

/*
 Example of usage
 */

class ViewController: UIViewController {

    weak var label: UILabel!

    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let label = UILabel()
        label.alpha = 0
        label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
        label.text = "Hello World!"
        label.textColor = .black
        view.addSubview(label)
        self.label = label

        let button = UIButton(type: .custom)
        button.frame = CGRect(x: 0, y: 250, width: 300, height: 100)
        button.setTitle("Press to Start FadeIn", for: UIControl.State())
        button.backgroundColor = .red
        button.addTarget(self, action: #selector(startFadeIn), for: .touchUpInside)
        view.addSubview(button)

        self.view = view
    }

    /*
     Animation in action
     */
    @objc private func startFadeIn() {
        label.layer.add(FadeInAdnimation(), forKey: "fadeIn")
    }

}

0

Swift 5

Andere Antworten sind richtig, aber in meinem Fall muss ich andere Eigenschaften zu handhaben auch ( alpha, animate, completion). Aus diesem Grund habe ich ein wenig geändert, um diese Parameter wie folgt verfügbar zu machen:

extension UIView {
    /// Helper function to update view's alpha with animation
    /// - Parameter alpha: View's alpha
    /// - Parameter animate: Indicate alpha changing with animation or not
    /// - Parameter duration: Indicate time for animation
    /// - Parameter completion: Completion block after alpha changing is finished
    func set(alpha: CGFloat, animate: Bool, duration: TimeInterval = 0.3, completion: ((Bool) -> Void)? = nil) {
        let animation = { (view: UIView) in
            view.alpha = alpha
        }
    
        if animate {
            UIView.animate(withDuration: duration, animations: {
                animation(self)
            }, completion: { finished in
                completion?(finished)
            })
        } else {
            layer.removeAllAnimations()
            animation(self)
            completion?(true)
        }
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.