Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the easiest way to animate a line?

I am creating an app that involves animating lines within a workspace over time. My current approach for this is to use code like this in drawRect:

CGContextSetStrokeColor(context, black);
CGContextBeginPath(context);
CGContextMoveToPoint(context, startPoint.x, startPoint.y);
CGContextAddLineToPoint(context, finalPoint.x, finalPoint.y);
CGContextStrokePath(context);

...and then just setting a timer to run every 0.05 seconds to update finalPoint and call setNeedsDisplay.

I'm finding this approach (when there's 5ish lines moving at once) slows down the app terribly, and even with such a high refresh frequency, still appears jerky.

There must be some better way to perform this very simple line drawing in an animated line - i.e. saying that I want a line to start at x1, y1 and stretching to x2, y2 over a given length of time. What are my options for this? I need to make this perform faster and would love to get rid of this clunky timer.

Thanks!

like image 246
user700774 Avatar asked Jul 21 '11 08:07

user700774


1 Answers

Use CAShapeLayers, and a combination of CATransactions and CABasicAnimation.

You can add a given path to a shapeLayer and let it do the rendering.

A CAShapeLayer object has two properties called strokeStart and strokeEnd, which defines where along the path the end of the line should render. The defaults are 0.0 for strokeStart, and 1.0 for strokeEnd.

If you set up your path so that strokeEnd initially starts at 0.0, you will see no line.

You can then animate, from 0.0 to 1.0, the strokeEnd property and you will see the line lengthen.

To change CAShapeLayer's implicit 0.25s default animation timing, you can add a function to the class, like so:

-(void)animateStrokeEnd:(CGFloat)_strokeEnd {
    [CATransaction begin];
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath];
    animation.duration = 2.0f; //or however long you want it to happen
    animation.fromValue = [NSNumber numberWithFloat:self.strokeEnd]; // from the current strokeEnd value
    animation.toValue = [NSNumber numberWithFloat:_strokeEnd]; //to the end of the path
    [CATransaction setCompletionBlock:^{ self.strokeEnd = _strokeEnd }];
    [self addAnimation:animation forKey:@"animateStrokeEnd"];
    [CATransaction commit];
}

You can pass any value from 0.0f to 1.0f as the value of _strokeEnd.

The setCompletionBlock: ensures that the value you are passing is explicitly set after the animation completes.

like image 144
C4 - Travis Avatar answered Oct 15 '22 16:10

C4 - Travis