¿Animar texto UILabel entre dos números?

80

Soy nuevo en la programación de iPhone y Mac (desarrollado para Windows antes), y tengo una pregunta:

¿Cómo puedo animar la textpropiedad de UILabelentre dos números, por ejemplo, del 5 al 80 en un estilo Ease-Out? ¿Es posible con CoreAnimation? He estado buscando en Google durante una hora, pero no he encontrado nada que solucione mi problema. Lo que quiero: Animar el dinero de los usuarios para un juego simple. No se ve muy bien cuando pasa de 50 a 100 o algo así sin animación.

¿Alguien tiene una idea de cómo hacer eso?

¡Gracias!

Markus Kasten
fuente
2
Esta es una pregunta antigua, pero Pop (marco de animación de Facebook) sería una buena solución. Puede animar la propiedad de texto directamente.
jrturton
Posible duplicado del cambio de texto
eonil

Respuestas:

160

Puede utilizar las transiciones automáticas. Funciona perfectamente bien:

// Add transition (must be called after myLabel has been displayed)
 CATransition *animation = [CATransition animation];
animation.duration = 1.0;
animation.type = kCATransitionFade;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[myLabel.layer addAnimation:animation forKey:@"changeTextTransition"];

// Change the text
myLabel.text = newText;

Este código funciona si myLabel ya se muestra. Si no, myLabel.layer será nulo y la animación no se agregará al objeto.


en Swift 4 eso sería:

let animation: CATransition = CATransition()
animation.duration = 1.0
animation.type = kCATransitionFade
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
myLabel.layer.add(animation, forKey: "changeTextTransition")
CedricSoubrie
fuente
2
Intenté esto (asegurándome de que la capa no sea nula cuando se agrega la animación), pero el texto aún no se anima. ¿Alguna otra trampa?
elsurudo
5
Solo una nota al margen, debe agregar la animación justo antes de cambiar el texto cada vez que desee cambiar el texto y que suceda el efecto de desvanecimiento. Sin embargo, no tiene que crear una nueva Transición cada vez, la misma instancia puede reutilizarse una y otra vez.
Lance
2
La cuestión era cómo animar los números, por ejemplo, incrementándolos en valor, no difuminando gráficamente entre los dos. Utilice PRTween: github.com/shu223/TweenDemo/tree/…
jowie
14
En realidad, si se establece removedOnCompletionque NOen el caso de CATransition, cada cambio en la década de etiqueta textserá animado.
Mark Adams
1
@kientux No hay nada especial en la clave changeTextTransition. Es simplemente una cadena que identifica la animación , lo que significa que es una cadena que puede usar más adelante para identificar una animación que agregó anteriormente. Si no necesita poder identificar su animación más adelante, solo puede especificar nil.
jamesk
27

¡Funciona bien!

C objetivo

[UIView transitionWithView:self.label 
                  duration:.5f 
                   options:UIViewAnimationOptionCurveEaseInOut | 
                           UIViewAnimationOptionTransitionCrossDissolve 
                animations:^{

    self.label.text = rand() % 2 ? @"111!" : @"42";

} completion:nil];

Swift 2

UIView.transitionWithView(label, duration: 0.25, options: [.CurveEaseInOut, .TransitionCrossDissolve], animations: {
    self.label.text = (arc4random() % 2 == 0) ? "111" : "222"
}, completion: nil)

Rápido 3, 4, 5

UIView.transition(with: label, duration: 0.25, options: [.curveEaseInOut, .transitionCrossDissolve], animations: {
    self.label.text = (arc4random() % 2 == 0) ? "111" : "222"
}, completion: nil)
Anton Gaenko
fuente
1
Trabajó también para otras propiedades, como cambiar el imagede aUIImageView
SaltyNuts
7

Encontré un gran motor para la interpolación de valores con una variedad de funciones de temporización diferentes llamado PRTween . Instale las clases y cree código siguiendo estas líneas:

- (IBAction)tweenValue
{
    [[PRTween sharedInstance] removeTweenOperation:activeTweenOperation];
    PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:0.0 endValue:100.0 duration:1.0];
    activeTweenOperation = [[PRTween sharedInstance] addTweenPeriod:period
                                                             target:self
                                                           selector:@selector(update:)
                                                     timingFunction:&PRTweenTimingFunctionCircOut];
}

- (void)update:(PRTweenPeriod*)period
{
    self.animatingView.center = CGPointMake(period.tweenedValue + 100.0, 200.0);
    self.valueLabel.text = [NSString stringWithFormat:@"%.2f", period.tweenedValue];
}

Funciona muy bien para mí. :)

jowie
fuente
5

Si desea que cuente hacia arriba y hacia abajo con el nuevo número eliminando el número anterior (como un ticker o algo así):

let animation = CATransition()
animation.removedOnCompletion = true
animation.duration = 0.2
animation.type = kCATransitionPush
animation.subtype = newValue > value ? kCATransitionFromTop : kCATransitionFromBottom
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
valueLabel.layer.addAnimation(animation, forKey:"changeTextTransition")
Adam Waite
fuente
¡Oye! ¡Gracias por tu respuesta! Esto funciona bastante bien. Solo tengo una pregunta adicional. ¿Sabes cómo animar solo partes del texto? ¿Te gusta el tercer personaje y dejar que el resto permanezca sin cambios? Me gustaría implementar una etiqueta que muestre números. Si el valor cambia, solo se animarán los dígitos, eso realmente cambió.
Lars Petersen
Personalmente, consideraría usar CoreGraphics y CoreAnimation para este tipo de cosas. ¿O podrías hacer trampa y unir un par de etiquetas? Depende de la complejidad de la cadena.
Adam Waite
3

En Swift 2.0, usando el UIView.transitionWithView()método:

UIView.transitionWithView(self.payPeriodSummaryLabel,
        duration: 0.2,
        options: [.CurveEaseInOut, .TransitionCrossDissolve],
        animations: { () -> Void in
            self.label.text = "your text value"
        }, completion: nil)
brandonscript
fuente
1

otra alternativa simple

extension UILabel {    
    func countAnimation(upto: Double) {
        let from: Double = text?.replace(string: ",", replacement: ".").components(separatedBy: CharacterSet.init(charactersIn: "-0123456789.").inverted).first.flatMap { Double($0) } ?? 0.0
        let steps: Int = 20
        let duration = 0.350
        let rate = duration / Double(steps)
        let diff = upto - from
        for i in 0...steps {
            DispatchQueue.main.asyncAfter(deadline: .now() + rate * Double(i)) {
                self.text = "\(from + diff * (Double(i) / Double(steps)))"
            }
        }
    }
}
Sergio
fuente