web-dev-qa-db-fra.com

Animer le changement de texte dans UILabel

Je règle une nouvelle valeur de texte sur UILabel. Actuellement, le nouveau texte semble très bien. Cependant, j'aimerais ajouter une animation lorsque le nouveau texte apparaît. Je me demande ce que je peux faire pour animer l'apparition du nouveau texte. 

100
Joo Park

Voici le code pour faire ce travail.

[UIView beginAnimations:@"animateText" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:1.0f];
[self.lbl setAlpha:0];
[self.lbl setText:@"New Text";
[self.lbl setAlpha:1];
[UIView commitAnimations];
17
Joo Park

Objectif c

Pour réaliser une transition vraie dissolution croisée (ancien fondu de libellé while nouveau fondu de fondu), vous ne voulez pas que le fondu devienne invisible. Il en résulterait scintillement indésirable même si le texte est inchangé.

Utilisez cette approche à la place:

CATransition *animation = [CATransition animation];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = kCATransitionFade;
animation.duration = 0.75;
[aLabel.layer addAnimation:animation forKey:@"kCATransitionFade"];

// This will fade:
aLabel.text = "New"

Voir aussi: Animer le texte UILabel entre deux nombres?

Démonstration sur iOS 10, 9, 8:

 Blank, then 1 to 5 fade transition


Testé avec Xcode 8.2.1 & 7.1, ObjectiveC sur iOS 10 à 8.0.

► Pour télécharger le projet complet, recherchez SO-3073520 in Swift Recipes .

149
SwiftArchitect

Je me demande si ça marche et ça marche parfaitement!

Objectif c

[UIView transitionWithView:self.label 
                  duration:0.25f 
                   options:UIViewAnimationOptionTransitionCrossDissolve 
                animations:^{

    self.label.text = Rand() % 2 ? @"Nice nice!" : @"Well done!";

  } completion:nil];

Swift 3

UIView.transition(with: label,
              duration: 0.25,
               options: .transitionCrossDissolve,
            animations: { [weak self] in
                self?.label.text = (arc4random()() % 2 == 0) ? "One" : "Two"
         }, completion: nil)
147
Anton Gaenko

Swift 4

Le bon moyen de fondre un UILabel (ou n'importe quel UIView pour cette question) est d'utiliser un Core Animation Transition. Cela ne clignotera pas et ne s'effacera pas en noir si le contenu reste inchangé.

Une solution portable et propre consiste à utiliser une Extension dans Swift (invoquer des éléments visibles auparavant modifiés)

// Usage: insert view.fadeTransition right before changing content
extension UIView {
    func fadeTransition(_ duration:CFTimeInterval) {
        let animation = CATransition()
        animation.timingFunction = CAMediaTimingFunction(name:
            kCAMediaTimingFunctionEaseInEaseOut)
        animation.type = kCATransitionFade
        animation.duration = duration
        layer.add(animation, forKey: kCATransitionFade)
    }
}

L'invocation ressemble à ceci:

// This will fade
aLabel.fadeTransition(0.4)
aLabel.text = "text"

 Blank, then 1 to 5 fade transition


► Trouvez cette solution sur GitHub et des détails supplémentaires sur Swift Recipes .

98
SwiftArchitect

depuis iOS4, cela peut évidemment être fait avec des blocs:

[UIView animateWithDuration:1.0
                 animations:^{
                     label.alpha = 0.0f;
                     label.text = newText;
                     label.alpha = 1.0f;
                 }];
21
Mapedd

Swift 2.0:

UIView.transitionWithView(self.view, duration: 1.0, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
    self.sampleLabel.text = "Animation Fade1"
    }, completion: { (finished: Bool) -> () in
        self.sampleLabel.text = "Animation Fade - 34"
})

OU 

UIView.animateWithDuration(0.2, animations: {
    self.sampleLabel.alpha = 1
}, completion: {
    (value: Bool) in
    self.sampleLabel.alpha = 0.2
})
3
A.G

Il s'agit d'une méthode d'extension C # UIView basée sur le code de @ SwiftArchitect. Lorsque la mise en page automatique est impliquée et que les contrôles doivent être déplacés en fonction du texte de l'étiquette, ce code d'appel utilise le Superview de l'étiquette en tant que vue de transition au lieu de l'étiquette elle-même. J'ai ajouté une expression lambda pour l'action afin de la rendre plus encapsulée.

public static void FadeTransition( this UIView AView, double ADuration, Action AAction )
{
  CATransition transition = new CATransition();

  transition.Duration = ADuration;
  transition.TimingFunction = CAMediaTimingFunction.FromName( CAMediaTimingFunction.Linear );
  transition.Type = CATransition.TransitionFade;

  AView.Layer.AddAnimation( transition, transition.Type );
  AAction();
}

Code d'appel:

  labelSuperview.FadeTransition( 0.5d, () =>
  {
    if ( condition )
      label.Text = "Value 1";
    else
      label.Text = "Value 2";
  } );
1
Gary Z

Solution Swift 4.2 (prendre la réponse 4.0 et mettre à jour pour compiler de nouveaux enums)

extension UIView {
    func fadeTransition(_ duration:CFTimeInterval) {
        let animation = CATransition()
        animation.timingFunction = CAMediaTimingFunction(name:
            CAMediaTimingFunctionName.easeInEaseOut)
        animation.type = CATransitionType.fade
        animation.duration = duration
        layer.add(animation, forKey: CATransitionType.fade.rawValue)
    }
}

func updateLabel() {
myLabel.fadeTransition(0.4)
myLabel.text = "Hello World"
}
1
Chris

Swift 4.2 version de la solution SwiftArchitect ci-dessus (fonctionne très bien):

    // Usage: insert view.fadeTransition right before changing content    

extension UIView {

        func fadeTransition(_ duration:CFTimeInterval) {
            let animation = CATransition()
            animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
            animation.type = CATransitionType.fade
            animation.duration = duration
            layer.add(animation, forKey: CATransitionType.fade.rawValue)
        }
    }

Invocation:

    // This will fade

aLabel.fadeTransition(0.4)
aLabel.text = "text"
1
winnie-ru

Si vous voulez faire ceci dans Swift avec un délai, essayez ceci:

delay(1.0) {
        UIView.transitionWithView(self.introLabel, duration: 0.25, options: [.TransitionCrossDissolve], animations: {
            self.yourLabel.text = "2"
            }, completion:  { finished in

                self.delay(1.0) {
                    UIView.transitionWithView(self.introLabel, duration: 0.25, options: [.TransitionCrossDissolve], animations: {
                        self.yourLabel.text = "1"
                        }, completion:  { finished in

                    })
                }

        })
    }

en utilisant la fonction suivante créée par @matt - https://stackoverflow.com/a/24318861/1982051 :

func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

qui deviendra ceci dans Swift 3

func delay(_ delay:Double, closure:()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.after(when: when, execute: closure)
}
0
ColossalChris

Selon vos goûts et vos besoins, vous pouvez choisir l’un des trois extraits de code suivants afin d’animer les modifications de texte de votre UILabel avec une animation à dissolution croisée:

1. Utilisation de transition(with:duration:options:animations:completion:)

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let label: UILabel = {
        $0.frame.Origin = CGPoint(x: 50, y: 50)
        $0.text = "Bob"
        $0.sizeToFit()
        return $0
    }(UILabel())

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white
        view.addSubview(label)

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
        view.addGestureRecognizer(tapGesture)
    }

    func toggle(_ sender: UITapGestureRecognizer) {
        let animation = {
            self.label.text = self.label.text == "Bob" ? "Dan" : "Bob"
        }
        UIView.transition(with: label, duration: 1, options: .transitionCrossDissolve, animations: animation, completion: nil)
    }

}

let controller = ViewController()
PlaygroundPage.current.liveView = controller

2. Utilisation de la propriété CATransition de CATransition et type

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let label: UILabel = {
        $0.frame.Origin = CGPoint(x: 50, y: 50)
        $0.text = "Bob"
        $0.sizeToFit()
        return $0
    }(UILabel())
    let animation: CATransition = {
        $0.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        $0.type = kCATransitionFade
        $0.duration = 1
        return $0
    }(CATransition())

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(label)

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
        view.addGestureRecognizer(tapGesture)
    }

    func toggle(_ sender: UITapGestureRecognizer) {
        label.layer.add(animation, forKey: nil)
        label.text = label.text == "Bob" ? "Dan" : "Bob"
        label.sizeToFit()
    }

}

let controller = ViewController()
PlaygroundPage.current.liveView = controller

3. Utilisation des paramètres CATransition et add(_:forKey:)key

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let label: UILabel = {
        $0.frame.Origin = CGPoint(x: 50, y: 50)
        $0.text = "Bob"
        $0.sizeToFit()
        return $0
    }(UILabel())
    let animation: CATransition = {
        $0.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        $0.duration = 1
        return $0
    }(CATransition())

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white
        view.addSubview(label)

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggle(_:)))
        view.addGestureRecognizer(tapGesture)
    }

    func toggle(_ sender: UITapGestureRecognizer) {
        label.layer.add(animation, forKey: kCATransitionFade)
        label.text = label.text == "Bob" ? "Dan" : "Bob"
        label.sizeToFit()
    }

}

let controller = ViewController()
PlaygroundPage.current.liveView = controller
0
Imanou Petit

Les valeurs système par défaut de 0,25 pour duration et de .curveEaseInEaseOut pour timingFunction sont souvent préférables pour la cohérence entre les animations et peuvent être omises:

let animation = CATransition()
label.layer.add(animation, forKey: nil)
label.text = "New text"

ce qui revient à écrire ceci:

let animation = CATransition()
animation.duration = 0.25
animation.timingFunction = .curveEaseInEaseOut
label.layer.add(animation, forKey: nil)
label.text = "New text"
0
nobody ever

Solution d'extension UILabel

extension UILabel{
  // created to make the code simpler for future used
  // and still can used fadeTransition 
  func textWithAnimation(text:String,duration:CFTimeInterval){
    fadeTransition(duration)
    self.text = text
  }

  //followed from @Chris and @winnie-ru
  func fadeTransition(_ duration:CFTimeInterval) {
    let animation = CATransition()
    animation.timingFunction = CAMediaTimingFunction(name:
        CAMediaTimingFunctionName.easeInEaseOut)
    animation.type = CATransitionType.fade
    animation.duration = duration
    layer.add(animation, forKey: CATransitionType.fade.rawValue)
  }
}

Fonction simplement appelée par  

uiLabel.textWithAnimation(text: "text you want to replace", duration: 0.2)

Merci pour tous les conseils les gars. J'espère que cela aidera à long terme

0
Muhammad Asyraf

Il existe une solution supplémentaire pour y parvenir. Il a été décrit ici . L'idée est de sous-classer UILabel et de remplacer la fonction action(for:forKey:) de la manière suivante:

class LabelWithAnimatedText: UILabel {
    override var text: String? {
        didSet {
            self.layer.setValue(self.text, forKey: "text")
        }
    }

    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
        if event == "text" {
            if let action = self.action(for: layer, forKey: "backgroundColor") as? CAAnimation {
                let transition = CATransition()
                transition.type = kCATransitionFade

                //CAMediatiming attributes
                transition.beginTime = action.beginTime
                transition.duration = action.duration
                transition.speed = action.speed
                transition.timeOffset = action.timeOffset
                transition.repeatCount = action.repeatCount
                transition.repeatDuration = action.repeatDuration
                transition.autoreverses = action.autoreverses
                transition.fillMode = action.fillMode

                //CAAnimation attributes
                transition.timingFunction = action.timingFunction
                transition.delegate = action.delegate

                return transition
            }
        }
        return super.action(for: layer, forKey: event)
    }
}

Exemples d'utilisation:

// do not forget to set the "Custom Class" IB-property to "LabelWithAnimatedText"
// @IBOutlet weak var myLabel: LabelWithAnimatedText!
// ...

UIView.animate(withDuration: 0.5) {
    myLabel.text = "I am animated!"
}
myLabel.text = "I am not animated!"
0
Roman Aliyev