¿Cómo animar la propiedad textColor de un UILabel?

82

Por alguna razón, cuando intento animar textColor, no funcionará. El color del texto cambia repentinamente de A a B. ¿Es posible animarlo, de digamos rojo a negro?

dontWatchMyProfile
fuente

Respuestas:

6

Esta respuesta es obsoleta y no es una buena solución para la pregunta original. La respuesta de @strange a continuación es mucho mejor y debe usarse en lugar de esta respuesta: https://stackoverflow.com/a/20892927/76559

// Antigua respuesta a continuación

La textColorpropiedad no está especificada como animable en los documentos, por lo que no creo que pueda hacerlo con un simple bloque de animaciones UIView ...

Esto probablemente podría hacerse de forma bastante tosca con un NSTimerdisparo cada par de milisegundos, cada vez estableciendo el color gradualmente de uno a otro.

Digo que esto es crudo porque requeriría una matriz o algún otro contenedor de valores de color preestablecidos que van desde el color de inicio hasta el color de finalización, y estoy seguro de que hay una manera de hacer esto usando animación central o algo así, simplemente no No sé lo que es.

Jasarien
fuente
o: una función que arroja una matriz con valores RGB entre A y B y un porcentaje dado. Sin embargo, no sé nada sobre algoritmos de color.
dontWatchMyProfile
aquí hay buenas soluciones: aquí y aquí gracias a Anna Karenina
chacal
4
Debería usar en CADisplayLinklugar de NSTimermanejar animaciones manualmente porque está sincronizado con las actualizaciones de pantalla. Consulte la sesión 236 de la WWDC 2014: Creación de interacciones interrumpibles y receptivas aproximadamente a las 13:00.
Douglas Hill
esta ya NO debería ser la respuesta aceptada, incluso si fuera cierta en ese momento. vea la respuesta de extraño a continuación
bitwit
Stack Overflow no me permitirá eliminar esta respuesta obsoleta, ya que ha sido aceptada. Mira la respuesta de @ strange a continuación.
Jasarien
194

En cambio, ¿ha intentado usar una transición de fundido cruzado en el objeto en sí de esta manera, le dará un efecto agradable de fundido de entrada y salida de un color a otro:

C objetivo

[UIView transitionWithView:myLabel duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
    myLabel.textColor = NEW_COLOR;
} completion:^(BOOL finished) {
}];

Rápido

UIView.transitionWithView(creditsLabel, duration: 0.25, options: .TransitionCrossDissolve, animations: {     
    self.creditsLabel.textColor = UIColor.redColor() 
}, 
completion: nil)

Esto es mejor que usar NSTimers, CATextLayers, etc., por varias razones. CATextLayer no tiene el soporte adecuado para el kerning de texto o NSAttributedText, y los NSTimers están retrasados ​​(además hay demasiado código). La animación de transición anterior hace el truco y también se puede usar en una animación en cadena. Tuve el mismo problema y ya probé las soluciones anteriores, pero este código simple funciona de maravilla.

extraño
fuente
7
Agradable, elegante, en realidad la mejor y más limpia solución.
maksa
17
Excelente. Funciona en Swift de la misma manera:UIView.transitionWithView(creditsLabel, duration: 0.3, options: .TransitionCrossDissolve, animations: { self.creditsLabel.textColor = UIColor.redColor() }, completion: nil)
SimplGy
8
solo una nota: esto solo funciona cuando la etiqueta es estática. Si hace esto y se modifica la posición de la etiqueta, la animación de desvanecimiento mostrará un artefacto feo.
Lukas Petr
No me funciona en Xcode 10.2.1 y Swift 5. El método 'shokaveli' a continuación sí lo hace
Martin
He estado buscando una forma de hacer esto en SwiftUI, pero no parece compatible en ese momento.
philipp
58

Solución Swift 4 :

UIView.transition(with: yourLabel, duration: 0.3, options: .transitionCrossDissolve, animations: {
  self.yourLabel.textColor = .red
}, completion: nil)
budidino
fuente
Tenga en cuenta que esto solo funciona si tiene una instancia de UILabelpara la withpropiedad. Si haces algo como transition(with: outerView.label…)e intentas colocarlo dentro, fallará silenciosamente.
Sam Soffes
No funciona para mí por alguna razón. De repente, está haciendo el cambio en lugar de ser gradual durante la animación. :(
ScottyBlades
1
@ScottyBlades ¿tal vez estás haciendo la animación en el hilo de fondo? Intente envolver el código UIView.transition dentro de los corchetes DispatchQueue.main.async {}.
Budidino
1
FYI - La primera vez que lo intenté no funcionó y eso fue porque options: .easeInOutlo hice, así que lo cambié .transitionCrossDissolve y funcioné.
LeoGalante
13

La razón por la que textColor no es animable es que UILabel usa un CALayer regular en lugar de un CATextLayer.

Para hacer animable textColor (así como texto, fuente, etc.) podemos subclasificar UILabel para que use un CATextLayer.

Esto es bastante trabajo, pero afortunadamente ya lo hice :-)

Puede encontrar una explicación completa + un reemplazo de código abierto para UILabel en este artículo

Adamsiton
fuente
9

Puede intentar crear otra instancia de UILabel o lo que sea que tenga el textColor, y luego aplicar la animación entre esas dos instancias (la con el antiguo textColor y la que tiene el nuevo textColor).

benasher44
fuente
7

Esto fue lo ÚNICO que funcionó para mí:

let changeColor = CATransition()
changeColor.duration = 1

CATransaction.begin()

CATransaction.setCompletionBlock {
    selected.label.layer.addAnimation(changeColor, forKey: nil)
    selected.label.textColor = .blackColor()
}

selected.nameLabel.textColor = .redColor()

CATransaction.commit()
shokaveli
fuente
6

Aquí está mi código para animar el color del texto de la etiqueta. La parte importante es establecer textColor en clearColor antes de la animación.

label.textColor = [UIColor clearColor];
[UIView transitionWithView:label duration:duration/4 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
    label.textColor = self.highlightedCellPrimaryTextColor;
} completion:^(BOOL finished) { }];
servalex
fuente
0

Me resultó bastante fácil colocar una UIView debajo de la etiqueta y animar su opacidad. La etiqueta debe agregarse a esa vista. Quizás no sea una buena solución desde el punto de vista del consumo de recursos, pero bastante sencilla.

catchakos
fuente
0

actualizado swift 3.0

Acabo de cambiar los comentarios de @budidino

UIView.transition(with: my.label, duration: 0.3, options: .transitionCrossDissolve, animations: { my.label.textColor = .black }, completion: nil)
Shawn Baek
fuente
0

Gracias por la respuesta de @ Strange , funcionando perfectamente en Swift 5, Xcode 11 con un pequeño cambio de sintaxis. Estaba animando el color del texto para múltiples UILabels, si este también es tu caso, prueba esto

for label in [label1, label2, ...] as [UILabel] { // loop through a @IBOutlet UILabel array
        UIView.transition(with: label, duration: 0.3, options: .transitionCrossDissolve, animations: {
            label.textColor = .label
        }, completion: nil)
}
Daniel Hu
fuente