2012-03-18 15 views
7

Intento animar el dibujo de un UIBeizerPath (en mi ejemplo, un triángulo) en una subclase de UIView. Sin embargo, la subvista completa está animando en lugar de la forma.Cómo animar a CoreGraphics Dibujo de forma mediante CAKeyframeAnimation

¿Hay algo que me falta con la animación?

- (void)drawRect:(CGRect)rect { 

    CAShapeLayer *drawLayer = [CAShapeLayer layer]; 

    drawLayer.frame   = CGRectMake(0, 0, 100, 100); 
    drawLayer.strokeColor  = [UIColor greenColor].CGColor; 
    drawLayer.lineWidth  = 4.0; 

    [self.layer addSublayer:drawLayer]; 

    UIBezierPath *path = [UIBezierPath bezierPath]; 

    [path moveToPoint:CGPointMake(0,0)]; 
    [path addLineToPoint:CGPointMake(50,100)]; 
    [path addLineToPoint:CGPointMake(100,0)]; 
    [path closePath]; 

    CGPoint center = [self convertPoint:self.center fromView:nil]; 

    [path applyTransform:CGAffineTransformMakeTranslation(center.x, center.y)]; 

    [[UIColor redColor] set]; 

    [path fill]; 

    [[UIColor blueColor] setStroke]; 

    path.lineWidth = 3.0f; 

    [path stroke]; 

    CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; 

    pathAnimation.duration  = 4.0f; 
    pathAnimation.path   = path.CGPath; 
    pathAnimation.calculationMode = kCAAnimationLinear; 

    [drawLayer addAnimation:pathAnimation forKey:@"position"]; 
} 
+0

explicar exactamente lo que "animar el dibujo de un UIBezierPath" significa. ¿Desea dibujar los segmentos individuales, uno tras otro, o qué? –

+0

@kurt sí Me gustaría animar el dibujo de cada punto para que el triángulo parezca estar animado –

Respuesta

17
  • Está creando un CAShapeLayer, pero luego no hacer nada útil con él. Arreglemos eso.

  • No instale capas y animaciones en -drawRect:, porque eso es estrictamente un momento para hacer dibujos utilizando las API de CoreGraphics o UIKit. En su lugar, desea que CAShapeLayer dibuje el triángulo, de esa forma puede animarlo.

  • CAKeyframeAnimation.path está diseñado para algo completamente diferente (por ejemplo, mover una capa a lo largo de una ruta).

  • Su animación está animando el valor position de la capa. ¡No es de extrañar que mueva la capa! En su lugar, desea animar el valor path.

  • La idea detrás de CAKeyframeAnimation es que le proporcione una matriz de values para establecer las propiedades de la capa. Durante el tiempo entre fotogramas clave, se interpolará entre los dos fotogramas clave adyacentes. Entonces debes darle varias rutas, una para cada lado.

  • La interpolación de rutas arbitrarias es difícil. La interpolación de ruta de CA funciona mejor cuando las rutas tienen el mismo número y tipo de elementos. Entonces, nos aseguramos de que todos nuestros caminos tengan la misma estructura, solo que con algunos puntos uno encima del otro.

  • El secreto para la animación, y tal vez para las computadoras en general: usted debe sea preciso al explicar lo que quiere que suceda. "Quiero animar el dibujo de cada punto, por lo que parece estar animado", no es información suficiente.

Aquí es una subclase UIView que yo creo hace lo que estás pidiendo, o al menos cerca. Para animar, enganche un botón hasta la acción -animate:.

SPAnimatedShapeView.h:

#import <UIKit/UIKit.h> 

@interface SPAnimatedShapeView : UIView 

- (IBAction)animate:(id)sender; 

@end 

SPAnimatedShapeView.m:

#import "SPAnimatedShapeView.h" 
#import <QuartzCore/QuartzCore.h> 

@interface SPAnimatedShapeView() 
@property (nonatomic, retain) CAShapeLayer* shapeLayer; 
@end 

@implementation SPAnimatedShapeView 

@synthesize shapeLayer = _shapeLayer; 

- (void)dealloc 
{ 
    [_shapeLayer release]; 
    [super dealloc]; 
} 

- (void)layoutSubviews 
{ 
    if (!self.shapeLayer) 
    { 
     self.shapeLayer = [[[CAShapeLayer alloc] init] autorelease]; 
     self.shapeLayer.bounds = CGRectMake(0, 0, 100, 100);  // layer is 100x100 in size 
     self.shapeLayer.position = self.center;     // and is centered in the view 
     self.shapeLayer.strokeColor = [UIColor blueColor].CGColor; 
     self.shapeLayer.fillColor = [UIColor redColor].CGColor; 
     self.shapeLayer.lineWidth = 3.f; 

     [self.layer addSublayer:self.shapeLayer]; 
    } 
} 

- (IBAction)animate:(id)sender 
{ 
    UIBezierPath* path0 = [UIBezierPath bezierPath]; 
    [path0 moveToPoint:CGPointZero]; 
    [path0 addLineToPoint:CGPointZero]; 
    [path0 addLineToPoint:CGPointZero]; 
    [path0 addLineToPoint:CGPointZero]; 

    UIBezierPath* path1 = [UIBezierPath bezierPath]; 
    [path1 moveToPoint:CGPointZero]; 
    [path1 addLineToPoint:CGPointMake(50,100)]; 
    [path1 addLineToPoint:CGPointMake(50,100)]; 
    [path1 addLineToPoint:CGPointMake(50,100)]; 

    UIBezierPath* path2 = [UIBezierPath bezierPath]; 
    [path2 moveToPoint:CGPointZero]; 
    [path2 addLineToPoint:CGPointMake(50,100)]; 
    [path2 addLineToPoint:CGPointMake(100,0)]; 
    [path2 addLineToPoint:CGPointMake(100,0)]; 

    UIBezierPath* path3 = [UIBezierPath bezierPath]; 
    [path3 moveToPoint:CGPointZero]; 
    [path3 addLineToPoint:CGPointMake(50,100)]; 
    [path3 addLineToPoint:CGPointMake(100,0)]; 
    [path3 addLineToPoint:CGPointZero]; 

    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"path"];  
    animation.duration = 4.0f; 
    animation.values = [NSArray arrayWithObjects:(id)path0.CGPath, (id)path1.CGPath, (id)path2.CGPath, (id)path3.CGPath, nil]; 
    [self.shapeLayer addAnimation:animation forKey:nil]; 
} 

@end 
+0

Muchas gracias la explicación. Esto realmente ayuda. –

+5

Resulta que hay una manera aún más fácil: animar la propiedad 'strokeEnd' utilizando una' CABasicAnimation' de 0 a 1. [Explicación y código de ejemplo aquí] (http://oleb.net/blog/2010/12/animating-drawing -of-cgpath-with-cashapelayer /). –

Cuestiones relacionadas