2009-09-25 13 views
18

Estoy tratando de crear un "cursor intermitente" personalizado en UIKit, lo he intentado como se muestra a continuación, teniendo 2 funciones que básicamente siguen llamándose entre sí hasta que se oculta el cursor. Pero esto lleva a una buena recursión infinita ... por alguna razón las funciones se llaman entre sí de inmediato, no cada medio segundo como se espera.¿Cómo hacer que un cursor parpadee (o parpadee) en el iphone?

Me trataron de regresar si el parámetro 'terminado' no es SÍ (eliminando el comentario de la línea 'if (! Bien)'), pero que no conduce a ninguna animación en todo ...

Cualquier idea mejor? Perdí algo, ¿hay alguna manera mucho más fácil de hacer un "cursor parpadeante"?

- (void)onBlinkIn:(NSString *)animationID finished:(BOOL)ok context:(void *)ctx { 
if (cursorView.hidden) return; 
//if (!ok) return; 
[UIView beginAnimations:nil context:UIGraphicsGetCurrentContext()]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5f]; 
[UIView setAnimationDelegate:self]; 
[UIView setAnimationDidStopSelector:@selector(onBlinkOut:finished:context:)]; 
cursorView.textColor = [UIColor grayColor]; 
[UIView commitAnimations]; 
} 

- (void)onBlinkOut:(NSString *)animationID finished:(BOOL)ok context:(void *)ctx { 
if (cursorView.hidden) return; 
[UIView beginAnimations:nil context:UIGraphicsGetCurrentContext()]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5f]; 
[UIView setAnimationDelegate:self]; 
[UIView setAnimationDidStopSelector:@selector(onBlinkIn:finished:context:)]; 
cursorView.textColor = [UIColor clearColor]; 
[UIView commitAnimations]; 
} 
+0

El parámetro de contexto es un puntero nulo, no un CGContextRef (aunque pasa un CGContextRef es válido, desde luego, no será útil) – rpetrich

Respuesta

16

En el delegado:

- (void)blinkAnimation:(NSString *)animationId finished:(BOOL)finished target:(UIView *)target 
{ 
    if (shouldContinueBlinking) { 
     [UIView beginAnimations:animationId context:target]; 
     [UIView setAnimationDuration:0.5f]; 
     [UIView setAnimationDelegate:self]; 
     [UIView setAnimationDidStopSelector:@selector(blinkAnimation:finished:target:)]; 
     if ([target alpha] == 1.0f) 
      [target setAlpha:0.0f]; 
     else 
      [target setAlpha:1.0f]; 
     [UIView commitAnimations]; 
    } 
} 

Y para iniciar la animación:

shouldContinueBlinking = YES; 
[self blinkAnimation:@"blinkAnimation" finished:YES target:cursorView]; 

Además, asegúrese de que su clase tiene una instancia de variable de shouldContinueBlinking

+2

Además, configurar el alfa en lugar del textColor permitirá que la GPU haga todo el dibujo y mejorará el rendimiento.Del mismo modo, hacer que cursorView sea una UIView y establecer el backgroundColor utilizará menos RAM y CPU que UILabel (y mucho menos que una UITextView o UITextField) – rpetrich

+0

¡Excelente! Esto es mucho mejor de lo que estaba buscando, y fácilmente reutilizable. –

+0

De los documentos para beginAnimations: context: "El uso de este método no se recomienda en iOS 4.0 y posteriores. Deberías usar los métodos de animación basados ​​en bloques para especificar tus animaciones " – drewish

0

Lo más probable es que esté bloqueando el bucle de evento principal y, por lo tanto, bloquee las animaciones cuando intente animar únicamente al finalizar.

En su lugar, configure un temporizador que se dispara después de 1/2 segundo que inicia la siguiente animación. Ese temporizador podría reiniciarse al final de la animación anterior, reduciendo así la carga y haciendo que su ritmo de parpadeo sea un poco más regular (pero tendrá que averiguar qué es lo más apropiado).

Consulte la documentación de la clase NSTimer.

Tenga en cuenta que cualquier tipo de animación constante como esta agotará la batería. No es un gran uno, por cualquier medio, pero aún así ... ...

+0

La animación no suele durar mucho, solo el tiempo para que alguien ingrese un número usando un teclado personalizado ... Hay varios números en la pantalla, y se supone que un cursor suave parpadeante simplemente hace que sea obvio qué número se está editando (el número está en una vista personalizada, no en un campo de texto). Creo que el impacto en la batería será insignificante (debido a la hora de ordenar) –

+0

Yah-- Acabo de mencionar la duración de la batería porque es una consideración adicional interesante en las plataformas móviles. – bbum

46

hacerlo de la manera Core Animation:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 
[animation setFromValue:[NSNumber numberWithFloat:1.0]]; 
[animation setToValue:[NSNumber numberWithFloat:0.0]]; 
[animation setDuration:0.5f]; 
[animation setTimingFunction:[CAMediaTimingFunction 
       functionWithName:kCAMediaTimingFunctionLinear]]; 
[animation setAutoreverses:YES]; 
[animation setRepeatCount:20000]; 
[[view layer] addAnimation:animation forKey:@"opacity"]; 

Donde ver es la UIView que desea parpadear. Core Animation lo hace muy conveniente porque revertirá automáticamente la animación. Tenga en cuenta que su duración completa es el doble de lo establecido en el campo de duración porque el valor que especifica se aplica a la dirección de avance. Si desea que la animación completa se ejecute (avance y retroceda) en la duración especificada, divida la duración a la mitad.

+0

¡Excelente también! No tengo el framework QuartzCore en mi aplicación, y no lo necesitaré, pero esta es una muy buena muestra que mantendré a mano para un futuro programa. Más complejo (me parece) que el "camino de UIView". –

+2

En lugar de 20000, debe usar HUGE_VALF. Entonces se repite para siempre –

+2

@ josema.vitaminew Solo quería repetir 20K veces. Para siempre sería demasiado. ;-) –

2
respuesta de

Matt Long en Swift 3:

func addOpacityAnimation(view: UIView) { 
    let key = "opacity" 
    let animation = CABasicAnimation(keyPath: key) 
    animation.fromValue = 1.0 
    animation.toValue = 0.0 
    animation.duration = 0.5 
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 
    animation.autoreverses = true 
    animation.repeatCount = FLT_MAX 
    view.layer.add(animation, forKey: key) 
} 
0
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; 
animation.keyPath = @"opacity"; 
animation.values = @[ @(0.0),@(0.0),@(1.0), @(1.0)]; 
animation.keyTimes = @[ @(0.001),@(0.49),@(0.50), @(1.0)]; 
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 
animation.duration = 1.2; 
animation.autoreverses = NO; 
animation.repeatCount= HUGE; 
[layer addAnimation:animation forKey:@"blink"]; 
Cuestiones relacionadas