<pre name="code" class="objc">可以适当加以封装,参考网址http://www.cocoachina.com/industry/20140705/9039.html
//
// ViewController.m
// CircleAnimationDemo
//
// Created by 程磊 on 15/5/3.
// Copyright (c) 2015年 程磊. All rights reserved.
//
#import "ViewController.h"
#define APP_WIDTH [UIScreen mainScreen].bounds.size.width
#define APP_HEIGHT [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property (nonatomic, strong) CAShapeLayer *currentProgressLayer;//当前的layer
@property (nonatomic, assign) CGFloat duration;//完成一圈动画需要的时间
@property (nonatomic, strong) NSMutableArray *progressLayers;//存放后加入的layer
@property (nonatomic, strong) UIBezierPath *circlePath;//贝塞尔曲线轨迹
@property (nonatomic, assign) CGFloat strokeWidth;//线条宽度
@property (nonatomic, strong) CAShapeLayer *backgroundLayer;//北京layer
@property (nonatomic, assign) BOOL isCircleComplete;//是否完成
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_duration = 45;
_strokeWidth = 6;
_progressLayers = [[NSMutableArray alloc] init];
_backgroundLayer = [CAShapeLayer layer];
_backgroundLayer.frame = CGRectMake(0, 0, 200, 200);
_backgroundLayer.position = CGPointMake((APP_WIDTH-200)/2, 100);
_backgroundLayer.anchorPoint = CGPointMake(0, 0);
_backgroundLayer.fillColor = [UIColor clearColor].CGColor;
_backgroundLayer.strokeColor = [UIColor lightGrayColor].CGColor;
_backgroundLayer.lineWidth = self.strokeWidth;
[self.view.layer addSublayer:_backgroundLayer];
_backgroundLayer.strokeStart = 0;
_backgroundLayer.strokeEnd = 1;
_circlePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 200, 200)];
_backgroundLayer.path = _circlePath.CGPath;
}
/**
* 添加新的shapeLayer
*
*/
- (void)addNewLayerstroke
{
CAShapeLayer *progressLayer = [CAShapeLayer layer];
progressLayer.path = self.circlePath.CGPath;
progressLayer.position = CGPointMake((APP_WIDTH-200)/2, 100);
progressLayer.anchorPoint = CGPointMake(0, 0);
progressLayer.strokeColor = [[self randomColor] CGColor];
progressLayer.fillColor = [[UIColor clearColor] CGColor];
progressLayer.lineWidth = 6.f;
progressLayer.strokeEnd = 0.f;
[self.view.layer addSublayer:progressLayer];
[self.progressLayers addObject:progressLayer];
self.currentProgressLayer = progressLayer;
}
/**
* 随机色
*
*/
- (UIColor *)randomColor {
return [UIColor colorWithRed:arc4random() % 256 / 256.f
green:arc4random() % 256 / 256.f
blue:arc4random() % 256 / 256.f
alpha:1];
}
/**
* 执行动画
* 上面代码中我们看到我们遍历了所有的CAShapeLayer,给每个strokeEnd添加了CABasicAnimation动画,然后给不是当前的layer的strokeStart属性添加了一个动画。再来看看duration,假设一圈代表45秒钟,这个意味着每次停止之后又开始的话duration肯定是减少的,所以用duration代表一圈剩余的可以录制的时间,再看strekeEndFinal,假设有很多段,肯定不是每个段的strkeEnd都是1所以这个是用来标识每段可以达到的最终距离一圈为(0-1)。最后我们需要更新background layer除去有彩色段剩余的地方。
你可能注意到上面的代码里面并没有移除动画,所以对于显示每一个CAShapeLayer我们设置都是通过layers的presentationLayer设置strokeStart和strokeEnd,然后移除CAShapeLayer上的所有动画。
presentationLayer在文档中是这么说的:
“While an animation is in progress, you can retrieve this object and use it to get the current values for those animations.”
*/
- (void)updateAnimations
{
CGFloat duration = self.duration * (1.f - [[self.progressLayers firstObject] strokeEnd]);//获取当前的执行动画需要的时间
CGFloat strokeEndFinal = 1.f;
for (CAShapeLayer *progressLayer in self.progressLayers)
{
CABasicAnimation *strokeEndAnimation = nil;
strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
strokeEndAnimation.duration = duration;
strokeEndAnimation.fromValue = @(progressLayer.strokeEnd);
strokeEndAnimation.toValue = @(strokeEndFinal);
strokeEndAnimation.autoreverses = NO;
strokeEndAnimation.repeatCount = 0.f;
CGFloat previousStrokeEnd = progressLayer.strokeEnd;
progressLayer.strokeEnd = strokeEndFinal;
[progressLayer addAnimation:strokeEndAnimation forKey:@"strokeEndAnimation"];
strokeEndFinal -= (previousStrokeEnd - progressLayer.strokeStart);
if (progressLayer != self.currentProgressLayer)
{
CABasicAnimation *strokeStartAnimation = nil;
strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
strokeStartAnimation.duration = duration;
strokeStartAnimation.fromValue = @(progressLayer.strokeStart);
strokeStartAnimation.toValue = @(strokeEndFinal);
strokeStartAnimation.autoreverses = NO;
strokeStartAnimation.repeatCount = 0.f;
progressLayer.strokeStart = strokeEndFinal;
[progressLayer addAnimation:strokeStartAnimation forKey:@"strokeStartAnimation"];
}
}
CABasicAnimation *backgroundLayerAnimation = nil;
backgroundLayerAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
backgroundLayerAnimation.duration = duration;
backgroundLayerAnimation.fromValue = @(self.backgroundLayer.strokeStart);
backgroundLayerAnimation.toValue = @(1.f);
backgroundLayerAnimation.autoreverses = NO;
backgroundLayerAnimation.repeatCount = 0.f;
backgroundLayerAnimation.delegate = self;
self.backgroundLayer.strokeStart = 1.0;
[self.backgroundLayer addAnimation:backgroundLayerAnimation forKey:@"strokeStartAnimation"];
}
/**
* 点击开始响应事件
*
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.isCircleComplete == NO) {
[self addNewLayerstroke];
[self updateAnimations];
}
}
/**
* 触摸结束时调用事件
*
*/
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.isCircleComplete == NO) {
[self removeAnimations];
}
}
- (void)removeAnimations
{
for (CAShapeLayer *progressLayer in self.progressLayers)
{
progressLayer.strokeStart = [progressLayer.presentationLayer strokeStart];
progressLayer.strokeEnd = [progressLayer.presentationLayer strokeEnd];
[progressLayer removeAllAnimations];
}
self.backgroundLayer.strokeStart = [self.backgroundLayer.presentationLayer strokeStart];
[self.backgroundLayer removeAllAnimations];
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if (self.isCircleComplete == NO && flag)
{
[self removeAnimations];
self.isCircleComplete = flag;
}
}
@end