ios - Anima el cambio de texto en UILabel
objective-c ipad (9)
Estoy configurando un nuevo valor de texto para un UILabel
. Actualmente, el nuevo texto parece estar bien. Sin embargo, me gustaría agregar algo de animación cuando aparece el nuevo texto. Me pregunto qué puedo hacer para animar la apariencia del nuevo texto.
C objetivo
Para lograr una verdadera transición de disolución cruzada (desvanecimiento de etiquetas antiguas mientras se desvanece la etiqueta nueva), no desea que se desvanezca a invisible. Provocaría un parpadeo no deseado incluso si el texto no se modifica .
Use este enfoque en su lugar:
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"
Ver también: animar el texto UILabel entre dos números?
Demostración en iOS 10, 9, 8:
Probado con Xcode 8.2.1 y 7.1 , ObjectiveC en iOS 10 a 8.0 .
► Para descargar el proyecto completo, busque SO-3073520 en Swift Recipes .
Swift 4
La forma correcta de desvanecer un UILabel (o cualquier UIView para ese asunto) es usar una Core Animation Transition
. Esto no parpadeará, ni se desvanecerá a negro si el contenido no se modifica.
Una solución portátil y limpia es usar una Extension
en Swift (invocar elementos visibles que cambian con anterioridad)
// 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)
}
}
La invocación se ve así:
// This will fade
aLabel.fadeTransition(0.4)
aLabel.text = "text"
► Encuentre esta solución en GitHub y detalles adicionales sobre SO-3073520 .
Aquí está el código para hacer que esto funcione.
[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];
De acuerdo con sus gustos y necesidades, puede elegir uno de los siguientes tres fragmentos de código para animar los cambios de texto de UILabel
con alguna animación de disolver cruzada:
1. Uso 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. Uso de la propiedad type
CATransition
y CATransition
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. Usando CATransition
y el parámetro de key
add(_:forKey:)
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
Este es un método de extensión C # UIView que se basa en el código de @ SwiftArchitect. Cuando la distribución automática está involucrada y los controles deben moverse según el texto de la etiqueta, este código de llamada usa la Supervisión de la etiqueta como vista de transición en lugar de la etiqueta misma. Agregué una expresión lambda para la acción para hacerlo más encapsulado.
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();
}
Código de llamada:
labelSuperview.FadeTransition( 0.5d, () =>
{
if ( condition )
label.Text = "Value 1";
else
label.Text = "Value 2";
} );
Me pregunto si funciona y funciona perfectamente.
C objetivo
[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)
Si desea hacer esto en Swift
con un retraso, intente esto:
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
})
}
})
}
usando la siguiente función creada por @matt - https://.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)
}
que se convertirá en esto en Swift 3
func delay(_ delay:Double, closure:()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.after(when: when, execute: closure)
}
desde iOS4 obviamente se puede hacer con bloques:
[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"
})
O
UIView.animateWithDuration(0.2, animations: {
self.sampleLabel.alpha = 1
}, completion: {
(value: Bool) in
self.sampleLabel.alpha = 0.2
})