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.
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];
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:
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 .
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)
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"
► Trouvez cette solution sur GitHub et des détails supplémentaires sur Swift Recipes .
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;
}];
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
})
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";
} );
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"
}
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"
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)
}
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:
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
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
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
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"
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
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!"