Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animating the drawing of a line

I'm trying to animate the drawing of a line by the following way:

.h

CAShapeLayer *rootLayer;
CAShapeLayer *lineLayer;
CGMutablePathRef path;

.m

 path = CGPathCreateMutable();
 CGPathMoveToPoint(path, nil, self.frame.size.width/2-100, 260);
 CGPathAddLineToPoint(path, nil, self.frame.size.width/2+100.0, 260);    
 CGPathCloseSubpath(path);

 self.rootLayer = [CALayer layer];
 rootLayer.frame = self.bounds;
[self.layer addSublayer:rootLayer];

 self.lineLayer = [CAShapeLayer layer];
[lineLayer setPath:path];
[lineLayer setFillColor:[UIColor redColor].CGColor];
[lineLayer setStrokeColor:[UIColor blueColor].CGColor];
[lineLayer setLineWidth:1.5];
[lineLayer setFillRule:kCAFillRuleNonZero];
[rootLayer addSublayer:lineLayer];

[self performSelector:@selector(startTotalLine) withObject:nil afterDelay:1.5];

- (void)startTotalLine
{    
      CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"animatePath"];
      [animation setDuration:3.5];
       animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
      [animation setAutoreverses:NO];
      [animation setFromValue:(id)path];
      [animation setToValue:(id)path];
      [lineLayer addAnimation:animation forKey:@"animatePath"];    
}

The line had drawn before the startTotalLine method is invoked. Also, the startTotalLine method doesn't affect the line.

I want it to animate the the line drawing from right to left.

like image 271
jkigel Avatar asked May 15 '12 14:05

jkigel


1 Answers

I would do it with an animated property.

To achieve this I would create a custom CALayer class - let's call it LineLayer. Define a startPoint property, and a length property. I'd then configure the length property to be "animatable".

The code for that would look something like the following:

// LineLayer.h
@interface LineLayer: CALayer

@property (nonatomic, assign) int length;
// This was omitted from the SO code snippet.
@property (nonatomic, assign) CGPoint startPoint;

@end

// LineLayer.m
@implementation LineLayer

@synthesize length = _length;
// This was omitted from the SO code snippet.
@synthesize startPoint= _startPoint;

- (id) initWithLayer:(id)layer 
{
    if(self = [super initWithLayer:layer]) 
    {
        if([layer isKindOfClass:[LineLayer class]]) 
        {
            // This bit is required for when we CA is interpolating the values.
            LineLayer *other = (LineLayer*)layer;
            self.length = other.length;
            self.startPoint = other.startPoint; // This was omitted.
        }
    }
    return self;
}

+ (BOOL)needsDisplayForKey:(NSString *)key 
{
    if ([key isEqualToString:@"length"]) {
        return YES;
    }
    return [super needsDisplayForKey:key];
}

- (void) setLength:(int)newLength
{
    if (newLength < 0) {
        return; // Fail early.
    }
    _length = newLength; 
    [self setNeedsDisplay]; 
} 

/*
    This should have been drawInContext:(CGContextRef)context
    - (void) drawRect:(CGRect) rect 
*/
- (void) drawInContext:(CGContextRef)context
{
    //...Do your regular drawing here.

    // This was omitted from the SO code snippet.
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetLineWidth(context, 2);
    CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);
    CGContextAddLineToPoint(context, _startPoint.x + _length, _startPoint.y);
    CGContextStrokePath(context);
}

@end

Then in your view controller you could use LineLayer like this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    LineLayer *lineLayer = [LineLayer new];

    // This was omitted from the SO code snippet.
    lineLayer.frame = CGRectMake(0, 0, 320, 480);
    [lineLayer setNeedsDisplay];
    // ---

    lineLayer.startPoint = CGPointMake(0, 100);
    lineLayer.length = 0;

    [self.view.layer addSublayer:lineLayer];

    // Now animate the changes to the length property
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"length"];
    anim.duration = 5; // Change should table about 5 mins.
    anim.fromValue = [NSNumber numberWithInt:0];
    anim.toValue = [NSNumber numberWithInt:200];

    [lineLayer addAnimation:anim forKey:@"animateLength"];
    lineLayer.length = 200;
    //Do clean up below...
}

Happy Coding :)

like image 137
haroldcampbell Avatar answered Sep 22 '22 14:09

haroldcampbell