CABasicAnimation originates from top right rather than center - ios

I have a circle that I animate growing outwards and getting bigger. Unfortunately despite me setting the anchorPoint it doesnt animate from the center outwards, it seems to lock position top left. What is going on?
See this image that depicts the circles off center
Code
- (void)setLayerProperties {
rippleLayer = [[CAShapeLayer alloc] init];
rippleLayer.fillColor = [UIColor clearColor].CGColor;
rippleLayer.strokeColor = _Color.CGColor;
//rippleLayer.contentsGravity = #"center";
rippleLayer.anchorPoint = CGPointMake(0.5,0.5);
rippleLayer.bounds = self.bounds;
rippleLayer.path = bezierPath.CGPath;
[self.layer addSublayer:rippleLayer];
}
// Now animate the circle outwards
rippleLayer.opacity = 1;
CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
[scale setFromValue:[NSNumber numberWithFloat:1.0f]];
[scale setToValue:[NSNumber numberWithFloat:2.0f]];
[scale setRepeatCount:1];
[scale setDuration:1.0f];
//[scale setRemovedOnCompletion:YES];
[scale setFillMode:kCAFillModeForwards];
[rippleLayer addAnimation:scale forKey:scale.keyPath];

To scale layer at it's center, you need to set layer's position.This may help you
I want to draw a Smooth animations in iOS using CAPropertyAnimations
define RADIANS(angle) ((angle) / 180.0 * M_PI)
CGPoint testCenter = CGPointMake(144.5, 230.0);
CAShapeLayer *aTestLayer = [CAShapeLayer layer];
aTestLayer.path = [UIBezierPath bezierPathWithArcCenter:**CGPointZero** radius:15.0 startAngle:RADIANS(0) endAngle:RADIANS(360) clockwise:YES].CGPath;
aTestLayer.fillColor = [UIColor clearColor].CGColor;
aTestLayer.strokeColor = [UIColor whiteColor].CGColor;
**aTestLayer.position = testCenter;**
aTestLayer.borderWidth = 2.0;
[self.view.layer addSublayer:aTestLayer];
CABasicAnimation *pulse = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
pulse.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
pulse.duration = 2;
pulse.repeatCount = HUGE_VALF;
pulse.autoreverses = YES;
pulse.fromValue = [NSNumber numberWithFloat:1.0];
pulse.toValue = [NSNumber numberWithFloat:2.0];
[aTestLayer addAnimation:pulse forKey:nil];

Related

How can I make a circular progress meter with using own picture?

I want to make a meter like this picture.
I have 2 meter images - color meter image and gray meter image.
And I want to make a mater as shown in the above image by using them.
But I don't have any idea.
I got some sample code for making circular meter and filling some color in it. Here is that code:
CAShapeLayer *circle=[CAShapeLayer layer];
circle.path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(29, 29) radius:27 startAngle:2*M_PI*0-M_PI_2 endAngle:2*M_PI*1-M_PI_2 clockwise:YES].CGPath;
circle.fillColor=[UIColor clearColor].CGColor;
circle.strokeColor=[UIColor greenColor].CGColor;
circle.lineWidth=4;
CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.duration=10;
animation.removedOnCompletion=NO;
animation.fromValue=#(0);
animation.toValue=#(1);
animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[circle addAnimation:animation forKey:#"drawCircleAnimation"];
[imageCircle.layer.sublayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
[imageCircle.layer addSublayer:circle];
If you have an idea,please share it with me.
(it is ok that your idea uses this cord or not)
Thank you.
Here's a fairly robust example, just use this as a template:
video show: https://www.youtube.com/watch?v=ucYqb0Gs1_8&feature=youtu.be
just call to the second method, and the second method will call the first method, and there you have it. Drop it into a view controllers view and you will see the magic happen:
#define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180)
-(void)this
{
[CATransaction begin];
[CATransaction setAnimationDuration:3.5];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
CABasicAnimation * drawAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
drawAnimation.removedOnCompletion = YES;
drawAnimation.autoreverses = YES;
drawAnimation.repeatCount = INFINITY;
drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawAnimation.toValue = [NSNumber numberWithFloat:1.f];
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[arc addAnimation:drawAnimation forKey:#"thisone"];
[CATransaction commit];
[CATransaction begin];
[CATransaction setAnimationDuration:3.5];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
CABasicAnimation *drawAnimation1 = [CABasicAnimation animationWithKeyPath:#"strokeStart"];
drawAnimation1.removedOnCompletion = YES;
drawAnimation1.autoreverses = YES;
drawAnimation1.repeatCount = INFINITY;
drawAnimation1.fromValue = [NSNumber numberWithFloat:0.0];
drawAnimation1.toValue = [NSNumber numberWithFloat:-1.0];
[arc addAnimation:drawAnimation1 forKey:#"myKey"];
[CATransaction commit];
}
-(void)doGradientoutline {
float th = 50.00;
UIView * hellowkitt = [UIView new];
[hellowkitt setFrame:CGRectMake(SCREEN_WIDTH/2-(30+th)*2/2-th, SCREEN_HEIGHT/4-th, (30+th)*2+th*2, (30+th)*2+th*2)];
[self.view addSubview: hellowkitt];
UIView * imageView = [UIView new];
[imageView setFrame:CGRectMake(th, th, hellowkitt.frame.size.width-th*2, hellowkitt.frame.size.height-th*2)];
[imageView setClipsToBounds:true];
[imageView.layer setCornerRadius:(hellowkitt.frame.size.width-th*2)/2];
[hellowkitt addSubview:imageView];
UIImageView * imageView1 = [UIImageView new];
[imageView1 setImage:[UIImage imageNamed:#"df"]];
[imageView1 setFrame:CGRectMake(hellowkitt.frame.origin.x+th, hellowkitt.frame.origin.y+th, hellowkitt.frame.size.width-th*2, hellowkitt.frame.size.height-th*2)];
[imageView1 setClipsToBounds:true];
[imageView1.layer setCornerRadius:imageView1.frame.size.height/2];
[self.view addSubview:imageView1];
int radius = imageView.frame.size.width/2+7;
arc = [CAShapeLayer layer];
[arc setFrame:imageView.frame];
UIBezierPath * aa =[UIBezierPath bezierPathWithArcCenter:CGPointMake(imageView.center.x, imageView.center.y) radius:radius startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(360) clockwise:YES];
arc.path = aa.CGPath;
arc.bounds = CGPathGetBoundingBox(aa.CGPath);
arc.frame = arc.bounds;
arc.fillColor = [UIColor clearColor].CGColor;
arc.strokeColor = [UIColor purpleColor].CGColor;
arc.lineWidth = 40;
[arc setLineCap:#"round"];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(0, 0, hellowkitt.frame.size.width, hellowkitt.frame.size.height);
gradientLayer.colors = #[(__bridge id)[UIColor paperColorRedA700].CGColor, (__bridge id)[UIColor paperColorBlueA700].CGColor];
gradientLayer.backgroundColor = (__bridge CGColorRef)((__bridge id)[UIColor blackBean].CGColor);
gradientLayer.startPoint = CGPointMake(0.0,0.5);
gradientLayer.endPoint = CGPointMake(1.0,0.51);
CABasicAnimation *drawAnimation11 = [CABasicAnimation animationWithKeyPath:#"colors"];
drawAnimation11.duration = 2.00;
drawAnimation11.repeatCount = HUGE_VAL;
drawAnimation11.removedOnCompletion = NO;
drawAnimation11.fillMode = kCAFillModeForwards;
drawAnimation11.autoreverses = true;
drawAnimation11.fromValue = #[(__bridge id)[UIColor paperColorRedA700].CGColor, (__bridge id)[UIColor paperColorBlueA700].CGColor];
drawAnimation11.toValue = #[(__bridge id)[UIColor redColor].CGColor, (__bridge id)[UIColor blueColor].CGColor];
drawAnimation11.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
animation.byValue = #(4 * M_PI);
animation.duration = 1.5f;
animation.repeatCount = INFINITY;
animation.removedOnCompletion = NO;
[self this];
gradientLayer.mask = arc;
[hellowkitt.layer addSublayer:gradientLayer];
[hellowkitt.layer addAnimation:animation forKey:#"fasdfaasdf"];
[gradientLayer addAnimation:drawAnimation11 forKey:#"thatone"];
}

Get Raw Curve from CABasicAnimation

I am animation the stokeColor of a line drawn to a CAShapeLayer with a CABasicAnimation instance. I wish to use the curve of this animation to 'animate' a non-animatible property. I want to control the volume of a sample which takes a float value in tandem with the evolution of the stokeColor. So, my basic animation animates between two strokeColors with a duration of 0.2f. How can I 'animate' the volume of my sample with this information, so that when the animation occurs so does the change in volume?
This animates color, stroke, position, and rotation, full example:
Here's a fairly robust example, just use this as a template:
video showcase of example: https://www.youtube.com/watch?v=ucYqb0Gs1_8&feature=youtu.be
just call to the second method, and the second method will call the first method, and there you have it. Drop it into a view controllers view and you will see the magic happen, feel free to manipulate the code to your needs:
#define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180)
-(void)this {
[CATransaction begin];
[CATransaction setAnimationDuration:3.5];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
CABasicAnimation * drawAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
drawAnimation.removedOnCompletion = YES;
drawAnimation.autoreverses = YES;
drawAnimation.repeatCount = INFINITY;
drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawAnimation.toValue = [NSNumber numberWithFloat:1.f];
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[arc addAnimation:drawAnimation forKey:#"thisone"];
[CATransaction commit];
[CATransaction begin];
[CATransaction setAnimationDuration:3.5];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
CABasicAnimation *drawAnimation1 = [CABasicAnimation animationWithKeyPath:#"strokeStart"];
drawAnimation1.removedOnCompletion = YES;
drawAnimation1.autoreverses = YES;
drawAnimation1.repeatCount = INFINITY;
drawAnimation1.fromValue = [NSNumber numberWithFloat:0.0];
drawAnimation1.toValue = [NSNumber numberWithFloat:-1.0];
[arc addAnimation:drawAnimation1 forKey:#"myKey"];
[CATransaction commit];
}
-(void)doGradientoutline {
float th = 50.00;
UIView * hellowkitt = [UIView new];
[hellowkitt setFrame:CGRectMake(SCREEN_WIDTH/2-(30+th)*2/2-th, SCREEN_HEIGHT/4-th, (30+th)*2+th*2, (30+th)*2+th*2)];
[self.view addSubview: hellowkitt];
UIView * imageView = [UIView new];
[imageView setFrame:CGRectMake(th, th, hellowkitt.frame.size.width-th*2, hellowkitt.frame.size.height-th*2)];
[imageView setClipsToBounds:true];
[imageView.layer setCornerRadius:(hellowkitt.frame.size.width-th*2)/2];
[hellowkitt addSubview:imageView];
UIImageView * imageView1 = [UIImageView new];
[imageView1 setImage:[UIImage imageNamed:#"df"]];
[imageView1 setFrame:CGRectMake(hellowkitt.frame.origin.x+th, hellowkitt.frame.origin.y+th, hellowkitt.frame.size.width-th*2, hellowkitt.frame.size.height-th*2)];
[imageView1 setClipsToBounds:true];
[imageView1.layer setCornerRadius:imageView1.frame.size.height/2];
[self.view addSubview:imageView1];
int radius = imageView.frame.size.width/2+7;
arc = [CAShapeLayer layer];
[arc setFrame:imageView.frame];
UIBezierPath * aa =[UIBezierPath bezierPathWithArcCenter:CGPointMake(imageView.center.x, imageView.center.y) radius:radius startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(360) clockwise:YES];
arc.path = aa.CGPath;
arc.bounds = CGPathGetBoundingBox(aa.CGPath);
arc.frame = arc.bounds;
arc.fillColor = [UIColor clearColor].CGColor;
arc.strokeColor = [UIColor purpleColor].CGColor;
arc.lineWidth = 40;
[arc setLineCap:#"round"];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(0, 0, hellowkitt.frame.size.width, hellowkitt.frame.size.height);
gradientLayer.colors = #[(__bridge id)[UIColor paperColorRedA700].CGColor, (__bridge id)[UIColor paperColorBlueA700].CGColor];
gradientLayer.backgroundColor = (__bridge CGColorRef)((__bridge id)[UIColor blackBean].CGColor);
gradientLayer.startPoint = CGPointMake(0.0,0.5);
gradientLayer.endPoint = CGPointMake(1.0,0.51);
CABasicAnimation *drawAnimation11 = [CABasicAnimation animationWithKeyPath:#"colors"];
drawAnimation11.duration = 2.00;
drawAnimation11.repeatCount = HUGE_VAL;
drawAnimation11.removedOnCompletion = NO;
drawAnimation11.fillMode = kCAFillModeForwards;
drawAnimation11.autoreverses = true;
drawAnimation11.fromValue = #[(__bridge id)[UIColor paperColorRedA700].CGColor, (__bridge id)[UIColor paperColorBlueA700].CGColor];
drawAnimation11.toValue = #[(__bridge id)[UIColor redColor].CGColor, (__bridge id)[UIColor blueColor].CGColor];
drawAnimation11.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
animation.byValue = #(4 * M_PI);
animation.duration = 1.5f;
animation.repeatCount = INFINITY;
animation.removedOnCompletion = NO;
[self this];
gradientLayer.mask = arc;
[hellowkitt.layer addSublayer:gradientLayer];
[hellowkitt.layer addAnimation:animation forKey:#"fasdfaasdf"];
[gradientLayer addAnimation:drawAnimation11 forKey:#"thatone"];
}
OH yeah, and one more thing, apple talked about some of this in 2014, they suggested using stroke to animate volume of sorts:
http://asciiwwdc.com/2014/sessions/419

CAAnimation not working as expected on CALayer

I am trying to animate the the appearance and then the disappearance of a UIBezierPath in a CAShapeLayer.
How I would like to do it is that at start, the path would be invisible by setting strokeStart and strokeEnd to 0. Then, in my animate method I would do a CABasicAnimation with setting the strokeEnd to 1, and after this is done, another animation where I set the strokeStart to 1, so the path would disappear again. Here is what I've tried:
- (void)animate
{
CAShapeLayer *layer = (CAShapeLayer *)self.layer;
CABasicAnimation *appearingAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
appearingAnimation.duration = _duration / 2.0;
appearingAnimation.fromValue = #0;
appearingAnimation.toValue = #1;
CABasicAnimation *disappearingAnimation = [CABasicAnimation animationWithKeyPath:#"strokeStart"];
disappearingAnimation.beginTime = _duration / 2.0;
disappearingAnimation.duration = _duration / 2.0;
disappearingAnimation.fromValue = #0;
disappearingAnimation.toValue = #1;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.duration = _duration;
animationGroup.animations = #[appearingAnimation, disappearingAnimation];
animationGroup.repeatCount = MAXFLOAT;
[layer addAnimation:animationGroup forKey:#"test"];
}
But the effect I am seeing is that the appearingAnimation is working properly, but as soon as it is done, the path instantly disappears without any animation. After this (_duration/2.0 time later) the whole thing starts over, so it would appear that the disappearingAnimation has no effect.
I tried another approach, but that only worked if the path was on my view.layer. As soon as I added it to a sublayer and tried to animate that one, the second (disappearing) animation had a glitch in it. Here is my second approach:
- (void)animate
{
CAShapeLayer *layer = (CAShapeLayer *)self.layer;
layer.strokeStart = 0;
layer.strokeEnd = 1;
[CATransaction begin];
[CATransaction setCompletionBlock:^{
layer.strokeStart = 1;
layer.strokeEnd = 1;
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[self animate];
}];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"strokeStart"];
animation.duration = _duration / 2.0;
animation.fromValue = [NSNumber numberWithDouble:0];
animation.toValue = [NSNumber numberWithDouble:1];
[layer addAnimation:animation forKey:#"animation1"];
[CATransaction commit];
}];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.duration = _duration / 2.0;
animation.fromValue = [NSNumber numberWithDouble:0];
animation.toValue = [NSNumber numberWithDouble:1];
[layer addAnimation:animation forKey:#"animation"];
[CATransaction commit];
}
Any idea why the first solution doesn't work at all, or why the second is only working properly on the view.layer and not on a sublayer?
When animating a layer property, you will want to set the layer property to the end value before adding the animation, as the animation changes are only applied to the presentation, not the model layer. Once the animation is completed it will be removed, leaving the layer in the state it was before.
Both the first and second methods you have outlined worked for me once a layer had been created (missing from your snippet):
- (void)animate
{
CAShapeLayer *layer = [CAShapeLayer layer];
CGFloat _duration = 2.0;
CGFloat radius = self.view.frame.size.width/2.0;
CGFloat startAngle = -(M_PI_2);
CGFloat endAngle = (3*M_PI_2);
CGPoint center = CGPointMake(self.view.frame.size.width/2.0, self.view.frame.size.height/2.0);
layer.path = [[UIBezierPath bezierPathWithArcCenter:center
radius:radius
startAngle:startAngle
endAngle:endAngle
clockwise:YES] CGPath];
layer.fillColor = [[UIColor clearColor] CGColor];
layer.strokeColor = [[UIColor blackColor] CGColor];
[self.view.layer addSublayer:layer];
... {animation code}
}
I think it is the problem of the value of _duration / 2.0. It may be the problem of floating number calculation.
Try not to halve the total duration but to make the durations of appearingAnimation and disappearingAnimation as the base duration:
#define DURATION_BASE 1
// You can choose the DURATION_BASE value whaterver you like
- (void)animate
{
CAShapeLayer *layer = (CAShapeLayer *)self.layer;
CABasicAnimation *appearingAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
appearingAnimation.duration = DURATION_BASE;
appearingAnimation.fromValue = #0;
appearingAnimation.toValue = #1;
CABasicAnimation *disappearingAnimation = [CABasicAnimation animationWithKeyPath:#"strokeStart"];
disappearingAnimation.beginTime = appearingAnimation.duration;
disappearingAnimation.duration = DURATION_BASE;
disappearingAnimation.fromValue = #0;
disappearingAnimation.toValue = #1;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.duration = appearingAnimation.duration+disappearingAnimation.duration;
animationGroup.animations = #[appearingAnimation, disappearingAnimation];
animationGroup.repeatCount = MAXFLOAT;
[layer addAnimation:animationGroup forKey:#"test"];
}
When you want to change durations of appearingAnimation and disappearingAnimation, you just need modify the code like
appearingAnimation.duration = DURATION_BASE*1.2;
disappearingAnimation.duration = DURATION_BASE*1.2;

CABasicAnimation is not triggered after creation of the layer

I have CALayer subclass. After creation of the layer I want to animate affineTransform of layer but without success. New value is set but the change is not animated. If I trigger the animation after 1 second everything works perfect.
RCLClockDialLayer *layer = [RCLClockDialLayer layer];
layer.frame = CGRectMake(center.x, center.y, 2, self.radius);
layer.center = center;
layer.radius = self.radius;
layer.width = width;
layer.backgroundColor = [UIColor blackColor].CGColor;
layer.color = [UIColor whiteColor];
layer.affineTransform = CGAffineTransformRotate(layer.affineTransform, RCLDegreesToRadians(270));
[self addSubLayer:layer];
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformRotate(transform, RCLDegreesToRadians(80));
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"affineTransform"];
animation.duration = .5;
animation.fromValue = [layer valueForKey:#"affineTransform"];
animation.toValue = [NSValue valueWithCGAffineTransform:transform];
animation.fillMode = kCAFillModeForwards;
animation.cumulative = YES;
animation.removedOnCompletion = NO;
layer.affineTransform = transform;
[layer addAnimation:animation forKey:#"affineTransform"];
This is my code. I have tried many different solutions but nothing works. Do someone know what is the reason for this?

Draw circle animation with rounded stroke in iOS

I'm trying to animate a circle being drawn in iOS 7 - which is quite easy.
My problem is that I need the stroke to have rounded ends. The way I'm trying to do that now is by adding another circle to the start position of the animation.
Then for the end that is moving, I need another circle to follow along. It's doing pretty much what I want, but I need it to use an easeInOutQuart timing which is turning out more difficult than I thought.
The result so far is this:
My code looks like this:
- (void) drawCircleAnimated {
int radius = 100;
CALayer *animationLayer = [CALayer layer];
animationLayer.frame = CGRectMake(20.0f, 64.0f, CGRectGetWidth(self.view.layer.bounds) - 40.0f, CGRectGetHeight(self.view.layer.bounds) - 84.0f);
[self.view.layer addSublayer:animationLayer];
CGRect pathRect = CGRectInset(animationLayer.bounds, 100.0f, 100.0f);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = animationLayer.bounds;
pathLayer.bounds = pathRect;
pathLayer.geometryFlipped = NO;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [[UIColor blackColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = 10.0f;
pathLayer.lineJoin = kCALineJoinBevel;
[animationLayer addSublayer:pathLayer];
[self addStartPointCircle];
CAShapeLayer* circleToMove = [self addStartPointCircle];
circleToMove.anchorPoint = CGPointZero;
[pathLayer addSublayer:circleToMove];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
pathAnimation.duration = 5.0;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
[pathLayer addAnimation:pathAnimation forKey:#"strokeEnd"];
CAKeyframeAnimation *penAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
penAnimation.duration = 5.0;
penAnimation.path = pathLayer.path;
penAnimation.calculationMode = kCAAnimationPaced;
penAnimation.delegate = self;
penAnimation.removedOnCompletion = NO;
[circleToMove addAnimation:penAnimation forKey:#"position"];
}
To achieve the easing function, I've added this to the penAnimation - but it doesn't change anything. I guest it will always follow the other animation?
penAnimation.values = [NSArray arrayWithObjects: // i.e., Rotation values for the 3 keyframes, in RADIANS
[NSNumber numberWithFloat:0.0 * M_PI],
[NSNumber numberWithFloat:0.75 * M_PI],
[NSNumber numberWithFloat:1.5 * M_PI], nil];
penAnimation.keyTimes = [NSArray arrayWithObjects: // Relative timing values for the 3 keyframes
[NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:.5],
[NSNumber numberWithFloat:1.0], nil];
penAnimation.timingFunctions = [NSArray arrayWithObjects:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn], // from keyframe 1 to keyframe 2
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], nil]; // from keyframe 2 to keyframe 3
This should be all you need to add.
pathLayer.lineCap = kCALineCapRound;

Resources