2012-03-18 16 views
7

Sto provando ad animare il disegno di un UIBeizerPath (nel mio esempio un triangolo) in una sottoclasse UIView. Tuttavia, l'intera sottoview si sta animando invece della forma.Come animare il disegno di forma di CoreGraphics usando CAKeyframeAnimation

C'è qualcosa che mi manca con l'animazione?

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

spiegare esattamente ciò che "animano il disegno di un UIBezierPath" si intende. Vuoi disegnare i singoli segmenti, uno dopo l'altro, o cosa? –

+0

@kurt yes Mi piacerebbe animare il disegno di ogni punto in modo che il triangolo sembrasse essere animato –

risposta

17
  • Si sta creando una CAShapeLayer, ma poi non fare nulla di utile con esso. Risolviamolo.

  • Non impostare livelli e animazioni in -drawRect:, poiché ciò è strettamente inteso come tempo per disegnare utilizzando le API CoreGraphics o UIKit. Invece, vuoi che CAShapeLayer disegni il triangolo - in questo modo puoi animarlo.

  • CAKeyframeAnimation.path è pensato per qualcosa di completamente diverso (ad esempio, lo spostamento di un livello lungo un percorso).

  • L'animazione sta animando il valore position del livello. Nessuna sorpresa che muova lo strato! Vuoi invece animare il valore path.

  • L'idea alla base di CAKeyframeAnimation consiste nel fornire una serie di values per impostare la proprietà del livello. Durante il tempo tra i fotogrammi chiave, interpolerà tra i due fotogrammi chiave adiacenti. Quindi è necessario dargli diversi percorsi - uno per ciascun lato.

  • L'interpolazione di percorsi arbitrari è difficile. L'interpolazione del percorso di CA funziona meglio quando i percorsi hanno lo stesso numero e tipo di elementi. Quindi, ci assicuriamo che tutti i nostri percorsi abbiano la stessa struttura, solo con alcuni punti uno sopra l'altro.

  • Il segreto dell'animazione, e forse dei computer in generale: è deve essere essere precisi nello spiegare cosa vuoi che accada. "Voglio animare il disegno di ogni punto, quindi sembra che sia animato" non è abbastanza informazioni.

Ecco una sottoclasse UIView che io penso fa quello che stai chiedendo, o almeno vicino. Per animare, agganciare un pulsante fino all'azione -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

Grazie mille per la spiegazione. Questo aiuta davvero. –

+5

Si scopre che c'è un modo ancora più semplice: animare la proprietà 'strokeEnd' usando un' CABasicAnimation' da 0 a 1. [Spiegazione e codice di esempio qui] (http://oleb.net/blog/2010/12/animating-drawing -di-cgpath-con-cashapelayer /). –

Problemi correlati