2012-10-09 9 views
6

Sto creando una semplice app in cui quando l'utente preme un pulsante, una serie di linee verranno disegnate sullo schermo e l'utente sarà in grado di vedere queste linee disegnate in tempo reale (quasi come un'animazione) .Disegno animazione

Il mio codice simile a questa (è stata semplificata):

UIGraphicsBeginImageContext(CGSizeMake(300,300)); 
CGContextRef context = UIGraphicsGetCurrentContext(); 

for (int i = 0; i < 100; i++) { 
    CGContextMoveToPoint(context, i, i); 
    CGContextAddLineToPoint(context, i+20, i+20); 
    CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]); 
    CGContextStrokePath(context); 
} 

UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 

UIGraphicsEndImageContext(); 

mio problema è che:

1) Non appena l'utente preme il pulsante, i blocchi UIThread fino a quando il disegno è fatto.

2) Non riesco a ottenere le linee da disegnare sullo schermo una alla volta - Ho provato a impostare l'UIImage direttamente all'interno del ciclo e ho anche provato a impostare un contenuto di livello all'interno del ciclo.

Come aggirare questi problemi?

+0

Questo aiuto? http://stackoverflow.com/questions/9245954/moving-an-image-along-a-series-of-cgpoints –

+0

che tipo di ritardo desideri? – nielsbot

+0

Un ritardo personalizzabile sarebbe buono - penso che Rob avesse quello che stavo cercando ... grazie per il vostro aiuto! – HHHH

risposta

16

Si dice "proprio come un'animazione". Perché non fare un'animazione reale, a la Core Graphics 'CABasicAnimation? Hai davvero bisogno di mostrarlo come una serie di linee, o è una corretta animazione ok?

Se si desidera animare il disegno effettivo della linea, si potrebbe fare qualcosa di simile:

#import <QuartzCore/QuartzCore.h> 

- (void)drawBezierAnimate:(BOOL)animate 
{ 
    UIBezierPath *bezierPath = [self bezierPath]; 

    CAShapeLayer *bezier = [[CAShapeLayer alloc] init]; 

    bezier.path   = bezierPath.CGPath; 
    bezier.strokeColor = [UIColor blueColor].CGColor; 
    bezier.fillColor  = [UIColor clearColor].CGColor; 
    bezier.lineWidth  = 5.0; 
    bezier.strokeStart = 0.0; 
    bezier.strokeEnd  = 1.0; 
    [self.view.layer addSublayer:bezier]; 

    if (animate) 
    { 
     CABasicAnimation *animateStrokeEnd = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
     animateStrokeEnd.duration = 10.0; 
     animateStrokeEnd.fromValue = [NSNumber numberWithFloat:0.0f]; 
     animateStrokeEnd.toValue = [NSNumber numberWithFloat:1.0f]; 
     [bezier addAnimation:animateStrokeEnd forKey:@"strokeEndAnimation"]; 
    } 
} 

Poi tutto quello che dovete fare è creare il UIBezierPath per la vostra linea, ad esempio:

- (UIBezierPath *)bezierPath 
{ 
    UIBezierPath *path = [UIBezierPath bezierPath]; 

    [path moveToPoint:CGPointMake(0.0, 0.0)]; 

    [path addLineToPoint:CGPointMake(200.0, 200.0)]; 

    return path; 
} 

Se lo si desidera, è possibile applicare una serie di linee in un singolo percorso, ad esempio qui è una forma curva serie approssimativamente sinusoidale di rami:

- (UIBezierPath *)bezierPath 
{ 
    UIBezierPath *path = [UIBezierPath bezierPath]; 
    CGPoint point = self.view.center; 

    [path moveToPoint:CGPointMake(0, self.view.frame.size.height/2.0)]; 

    for (CGFloat f = 0.0; f < M_PI * 2; f += 0.75) 
    { 
     point = CGPointMake(f/(M_PI * 2) * self.view.frame.size.width, sinf(f) * 200.0 + self.view.frame.size.height/2.0); 
     [path addLineToPoint:point]; 
    } 

    return path; 
} 

E queste non bloccano il filo principale.

A proposito, dovrai ovviamente aggiungere CoreGraphics.framework al numero Build Settings del tuo target con il numero Link Binary With Libraries.

+1

È eccellente, grazie! Solo un'altra domanda: sto chiamando [percorso addLineToPoint] molte volte (forse 1000+). Dopo aver implementato il tuo metodo, trovo che la mia applicazione e il dispositivo su cui è in esecuzione diventano estremamente lenti/a scatti. Ho profilato l'applicazione e non sembra che stia usando una quantità enorme di CPU - sai perché sarebbe? – HHHH

+0

@HHHH Potrei facilmente immaginare che questo tasserebbe il dispositivo. Una volta che inizi a superare, diciamo, 30 segmenti di linea al secondo, tanto più difficile sarà per l'app tenere il passo con l'animazione. Non so dove sia il cut-off (è 30/secondo? 60? 100? Non lo so), ma ad un certo punto, la quantità di tempo necessaria per tracciare i percorsi per un dato frame di l'animazione, più tempo ogni fotogramma richiederà. E una volta che l'animazione rallenta a meno di 30 fotogrammi al secondo, più a scatti sarà. Devi in ​​qualche modo ridurre il numero di segmenti di linea che devono essere disegnati al secondo. Sospiro. – Rob

+1

@HHHH Forse puoi impostare la durata dell'animazione su _x/y_ dove _x_ è il numero di segmenti di linea e _y_ è il numero di segmenti al secondo che sosterrai (una cifra che probabilmente vorrai sperimentare con , per capire che cosa puoi cavartela senza alcun sobbalzo, forse 30 o 60 o 100 o ...). – Rob