2009-09-25 23 views
18

Sto cercando di creare un "cursore lampeggiante" personalizzato in UIKit, ho provato come mostrato di seguito, avendo 2 funzioni che sostanzialmente continuano a chiamarsi l'un l'altra fino a quando il cursore non viene nascosto. Ma questo porta ad una bella ricorsione infinita ... per qualche motivo le funzioni si chiamano subito, non ogni mezzo secondo come previsto.Come fare un cursore lampeggiante (o lampeggiante) su iphone?

ho cercato di tornare se il parametro 'finito' non è SI (decommentando la linea 'if (! Ok)'), ma che porta a nessuna animazione a tutti ...

Qualche idea migliore? Mi sono perso qualcosa, c'è un modo molto più semplice per creare un "cursore lampeggiante"?

- (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

Il parametro context è un puntatore nullo, non un CGContextRef (anche se passa un CGContextRef è valida, certamente non sarà utile) – rpetrich

risposta

16

Sul delegato:

- (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]; 
    } 
} 

E per avviare l'animazione:

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

Inoltre, garantire la vostra classe ha un esempio shouldContinueBlinking variabile

+2

Inoltre, l'impostazione dell'alfa al posto di textColor consentirà alla GPU di eseguire tutto il disegno e migliorerà le prestazioni.Allo stesso modo, rendendo cursorView a UIView e impostando backgroundColor userà meno RAM e CPU di un UILabel (e molto meno di un UITextView o UITextField) – rpetrich

+0

Eccellente! Questo è molto meglio di quello che stavo andando e facilmente riutilizzabile –

+0

Dalla documentazione per beginAnimations: contesto: "L'uso di questo metodo è sconsigliato in iOS 4.0 e versioni successive. Dovresti usare i metodi di animazione basati su blocchi per specificare le tue animazioni ". – drewish

0

Molto probabilmente, si sta bloccando il ciclo degli eventi principale e, in tal modo, bloccando le animazioni quando si tenta di animare solo sul traguardo.

Invece, imposta un timer che scatta dopo 1/2 secondo che avvia l'animazione successiva. Quel timer potrebbe essere resettato alla fine dell'animazione precedente, riducendo così il carico e rendendo la frequenza di battito un po 'più regolare (ma dovrai capire qual è il più appropriato).

Vedere la documentazione della classe NSTimer.

Si noti che qualsiasi tipo di animazione costante come questo metterà a dura prova la batteria. Non è un grande uno, con qualsiasi mezzo, ma ... ancora ...

+0

L'animazione non dura molto a lungo di solito, solo il tempo per qualcuno di inserire un numero usando una tastiera personalizzata ... Ci sono diversi numeri sullo schermo, e un cursore lampeggiante morbido dovrebbe semplicemente rendere ovvio quale numero viene modificato (il numero è in una vista personalizzata, non in un campo di testo). Penso che l'impatto sulla batteria sarà trascurabile (a causa del tempo di ordinamento) –

+0

Yah-- Ho appena menzionato la durata della batteria perché è un'interessante considerazione aggiuntiva sulle piattaforme mobili. – bbum

46

farlo nel modo in 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"]; 

Dove vista è l'UIView che si desidera lampeggiare. Core Animation rende questo molto conveniente perché farà invertire automaticamente l'animazione per te. Tieni presente che la durata totale è il doppio di quanto impostato nel campo Durata poiché il valore specificato si applica alla direzione di inoltro. Se si desidera eseguire l'intera animazione (avanti e poi indietro) nella durata specificata, dividere la durata a metà.

+0

Eccellente anche! Non ho il framework QuartzCore nella mia app, e non ne ho bisogno, ma questo è un ottimo esempio che manterrò a portata di mano per un futuro programma. Più complesso (trovo) rispetto al "modo UIView". –

+2

Invece di 20000 dovresti usare HUGE_VALF. Quindi si ripete per sempre –

+2

@ josema.vitaminew Volevo solo che ripetesse 20K volte. Per sempre sarebbe troppo. ;-) –

2
risposta di

Matt Long a 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"]; 
Problemi correlati