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.
I think the easiest way to do what you want, is to present some UIView that is 1.5 pixel height and animate it's width. Ask me if I'm not clear.
I think your code doesn't work because your variable path
is not a layer property. Read manuals:
CABasicAnimation provides basic, single-keyframe animation capabilities for a layer property.
And you do something strange here:
[animation setFromValue:(id)path];
[animation setToValue:(id)path];
EDIT: I stumbled upon an article, and understood what you were try to achieve! Now I think the reason you failed is that you can animate path that doesn't change number of points. And now I thought you can create a path-line with two points. At first they are at same place and another path is the line you want to end up with. Now animate from first path to the second. I think it should work, but I'm not sure.
EDIT: Definitely! You need this guy's code. Git link.
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 :)
Here is my solution for your case using "UIBezierPath", "CAShapeLayer" and the property "strokeEnd":
.m file
@synthesize shapeLayer;
[self drawLine];
-(void)drawLine {
CGFloat X1 = self.frame.size.width/2-100;
CGFloat Y1 = 260;
CGFloat X2 = self.frame.size.width/2+100.0;
CGFloat Y2 = 260;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(X1, Y1)];
[path addLineToPoint:CGPointMake(X2, Y2)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 1.5;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
shapeLayer.strokeEnd =0;
[self.layer addSublayer:shapeLayer];
[self performSelector:@selector(startTotalLine) withObject:nil afterDelay:1.5];
}
- (void)startTotalLine {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 3.5f;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[animation setAutoreverses:NO];
[animation setFromValue:[NSNumber numberWithInt:0]];
[animation setToValue:[NSNumber numberWithInt:1]];
[shapeLayer addAnimation:animation forKey:@"animatePath"];
}
The default "strokeEnd" value is 1, so, make it 0 at the beginning (no line will appear). Btw, here is useful examples provided: http://jamesonquave.com/blog/fun-with-cashapelayer/
来源:https://stackoverflow.com/questions/10603391/animating-the-drawing-of-a-line