Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw circle animation with rounded stroke in iOS

Tags:

ios

animation

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:
iOS draw circle

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
like image 873
MartinHN Avatar asked Feb 21 '14 22:02

MartinHN


1 Answers

This should be all you need to add.

pathLayer.lineCap = kCALineCapRound;
like image 65
Craig Siemens Avatar answered Nov 15 '22 13:11

Craig Siemens