2012-10-09 29 views
6

Estoy creando una aplicación simple donde cuando el usuario presiona un botón, se dibujarán una serie de líneas en la pantalla y el usuario podrá ver estas líneas dibujadas en tiempo real (casi como una animación) .Animación de dibujo

Mi código es como la siguiente (se ha simplificado):

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

Mi problema es que:

1) Tan pronto como el usuario presiona el botón, la UIThread bloques hasta que el dibujo es hecho.

2) No puedo hacer que las líneas se dibujen en la pantalla de a una por vez. He intentado configurar el UIImage directamente dentro del ciclo y también intenté establecer el contenido de una capa dentro del ciclo.

¿Cómo puedo evitar estos problemas?

+0

¿Esto ayuda? http://stackoverflow.com/questions/9245954/moving-an-image-along-a-series-of-cgpoints –

+0

¿Qué tipo de retraso quieres? – nielsbot

+0

Un retraso personalizable sería bueno, creo que Rob tenía lo que estaba buscando ... ¡gracias por su ayuda! – HHHH

Respuesta

16

Dice "simplemente como una animación". ¿Por qué no hacer una animación real, a la Core Graphics 'CABasicAnimation? ¿De verdad necesitas mostrarlo como una serie de líneas, o está bien una animación correcta?

Si desea animar el dibujo real de la línea, se podría hacer algo como:

#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"]; 
    } 
} 

Entonces todo lo que tiene que hacer es crear el UIBezierPath para su línea, por ejemplo:

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

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

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

    return path; 
} 

Si lo desea, puede parchar un grupo de líneas en una sola ruta, por ejemplo aquí hay una serie de líneas en forma de curva casi sinusoidal:

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

Y estas no bloquean el hilo principal.

Por cierto, usted obviamente tiene que añadir el CoreGraphics.framework a Build Settings de bajo Link Binary With Libraries su objetivo.

+1

Eso es excelente, ¡gracias! Solo otra pregunta: llamo [ruta addLineToPoint] muchas veces (quizás 1000+). Después de implementar su método, descubrí que mi aplicación y el dispositivo se ejecutan se vuelven extremadamente lentos. Hice un perfil de la aplicación y no parece estar usando una gran cantidad de CPU. ¿Sabes por qué sería esto? – HHHH

+0

@HHHH Podría fácilmente imaginar que esto gravaría el dispositivo. Una vez que comience a exceder, digamos, 30 segmentos de línea por segundo, será más difícil para la aplicación mantenerse al día con la animación. No sé dónde está el punto de corte (¿es 30/segundo? ¿60? 100? No lo sé), pero en algún momento, la cantidad de tiempo que se tarda en trazar los caminos para un marco dado de la animación, más tiempo tomará cada fotograma. Y una vez que la animación disminuye a menos de 30 fotogramas por segundo, más desigual será. De alguna manera, debe reducir la cantidad de segmentos de línea que se deben dibujar por segundo. Suspiro. – Rob

+1

@HHHH Tal vez pueda establecer que la duración de la animación sea _x/y_ donde _x_ es el número de segmentos de línea y _y_ es el número de segmentos por segundo que apoyará (una cifra con la que probablemente quiera experimentar con , para descubrir de qué se puede salir sin sacudidas, tal vez 30 o 60 o 100 o ...). – Rob