0

I am currently trying to create a busy animation that looks like this:

enter image description here

The broken part of the loop continually spins around the circle to signal that an operation is in progress.

I am defining two circles using CAShapeLayer, one circle is 'filling in' the circle with strokeEnd and the other is 'clearing' with strokeStart. The 'clearing circle' starts 1/10 of the way in front of the 'filling circle':

NSInteger radius = self.frame.size.width / 2;
CGFloat lineWidth = radius / 7.5;

UIColor *color = [UIColor redColor];

//add the outer circle
_outerCircle1 = [CAShapeLayer layer];
_outerCircle1.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius].CGPath;
_outerCircle1.position = CGPointMake(0, 0);
_outerCircle1.strokeStart = 1;
_outerCircle1.fillColor = [UIColor clearColor].CGColor;
_outerCircle1.strokeColor = color.CGColor;
_outerCircle1.lineWidth = lineWidth;
[self.layer addSublayer:_outerCircle1];

_outerCircle2 = [CAShapeLayer layer];
_outerCircle2.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius].CGPath;
_outerCircle2.position = CGPointMake(0, 0);
_outerCircle2.strokeEnd = 0;
_outerCircle2.fillColor = [UIColor clearColor].CGColor;
_outerCircle2.strokeColor = color.CGColor;
_outerCircle2.lineWidth = lineWidth;
[self.layer addSublayer:_outerCircle2];

[self createAnimations];

Here is where I define the animations. When the 'clearing circle' gets all the way around the the circle, I have to start a new animation that finishes the rest of the animation, then starts the animation all over again:

- (void)createAnimations {
[CATransaction begin];
[CATransaction setCompletionBlock:^{
    [CATransaction begin];
    [CATransaction setCompletionBlock:^{
        [self createAnimations];
    }];

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.duration = .5;
    animation.fromValue = [NSNumber numberWithFloat:.9];
    animation.toValue = [NSNumber numberWithFloat:1];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    [_outerCircle2 addAnimation:animation forKey:@"fillingAnimation"];

    animation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
    animation.duration = .5;
    animation.fromValue = [NSNumber numberWithFloat:0];
    animation.toValue = [NSNumber numberWithFloat:.1];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    [_outerCircle2 addAnimation:animation forKey:@"clearingAnimation"];

    [CATransaction commit];
}];

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 5;
animation.fromValue = [NSNumber numberWithFloat:0];
animation.toValue = [NSNumber numberWithFloat:.9];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[_outerCircle2 addAnimation:animation forKey:@"fillingAnimation"];

animation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
animation.duration = 5;
animation.fromValue = [NSNumber numberWithFloat:.1];
animation.toValue = [NSNumber numberWithFloat:1];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[_outerCircle1 addAnimation:animation forKey:@"clearingAnimation"];

[CATransaction commit];

}

This code has the desired effect of continually animating the circle, but each time the completion block is triggered for either the main animation or the follow up animation, the animations stutter.

I am not sure of the best way to perform this animation. Can anyone help me improve it?? Thanks!

Dan
  • 468
  • 1
  • 4
  • 19

1 Answers1

2

To create a spinning animation, inside your createAnimations method, replace what you have with:

CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
spinAnimation.byValue = [NSNumber numberWithFloat:2.0f*M_PI];
spinAnimation.duration = 1.3;
spinAnimation.repeatCount = HUGE_VALF;
[self.viewThatHasTheDrawings.layer addAnimation:spinAnimation forKey:@"indeterminateAnimation"];

This will spin the animation forever.

To cancel the animation, use:

[self.viewThatHasTheDrawings.layer removeAllAnimations];
KerrM
  • 5,139
  • 3
  • 35
  • 60
  • That works, thanks!! Of course, after I submitted this question I started looking into animating rotations (and your post verified it)... I don't know why I didn't think of that earlier! – Dan Jul 28 '14 at 15:25
  • I found one issue with the above code. If I add the animation to my view using `self.layer addAnimation`, the animation appears to stop any time my table view gets refreshed (this view is in a table view cell). If I add the animation to my outer circle, it will rotate forever but it rotates around the upper left hand corner rather than the center of the view. How do I get this view to keep rotating?? – Dan Jul 28 '14 at 19:49
  • I figured it out. If I set `frame` instead of `position` for the outerCircle layer, it will appropriately rotate around the center of the frame. Previously the width and height were both set to 0. – Dan Jul 28 '14 at 20:18