IOS CALayer实现圆点绕圆周运动--CAKeyframeAnimation的使用

效果图如下:

 

android的做法是,扩展一个View然后画一个圆点,再通过一个动画来不改变这个圆点的座标即可。

IOS的做法一:展示这个小圆点方法同android,但是圆点的座标变换通过定时器,代码如下:

 

 

-(void) playAnim{

    NSDate *scheduledTime = [NSDate dateWithTimeIntervalSinceNow:0];
    NSTimer *timer = [[NSTimer alloc] initWithFireDate:scheduledTime
                                              interval:0.00000001
                                                target:self
                                              selector:@selector(task)
                                              userInfo:nil
                                               repeats:YES];
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
    
   

}

-(void)task {
    self.dAngle += 1;
    [self setNeedsDisplay];
    
}

-(void) stopAnim{

    
}

-(void) drawInContext:(CGContextRef)ctx{
    
    
    //画圆
    CGContextSetRGBStrokeColor(ctx,0.52f, 0.76f, 0.07f, 1.0f);
    
    CGContextSetLineWidth(ctx, 2.0);
    
    //    CGContextAddArc(ctx, self.frame.size.width / 2 - 10, self.frame.size.height / 2, 25, 0, PI, 0);
    //
    //    CGContextAddArc(ctx, self.frame.size.width / 2 + 10, self.frame.size.height / 2, 25, 0, PI, 0);
    
    
    /*
     CGContextRef c:上下文
     CGFloat x :x,y圆弧所在圆的中心点坐标
     CGFloat y :x,y圆弧所在圆的中心点坐标
     CGFloat radius :所在圆的半径
     CGFloat startAngle : 圆弧的开始的角度  单位是弧度  0对应的是最右侧的点;
     CGFloat endAngle  : 圆弧的结束角度
     int clockwise : 顺时针(0) 或者 逆时针(1)
     */
    CGContextAddArc(ctx, self.frame.size.width / 2, self.frame.size.height / 2, 25, 0,  2 * PI, 0);
    
    CGContextDrawPath(ctx, kCGPathStroke);
    
    
    //画一个圆点,,将上面的定时器开启可以达到圆点绕圆周运动
    CGContextSetRGBStrokeColor(ctx,0.12f, 0.26f, 0.07f, 1.0f);
    CGContextAddArc(ctx,
                    self.frame.size.width / 2 + cos(self.dAngle * PI / 180) * 25,
                    self.frame.size.height / 2 + sin(self.dAngle * PI / 180) * 25,
                    5,
                    0,
                    2 * PI,
                    0);
    CGContextDrawPath(ctx, kCGPathFillStroke);
    
}


@end


这种方法的缺点是是,小圆点的座标改变是线性变化,如果想达到淡入淡出的效果,需要自己支写动画插值器,难度有点大, 不推荐使用此方法。

 

 

针对方法一中的缺点,方法二有能有效解决这个问题。

方法二: 使用

CAKeyframeAnimation+UIBezierPath

 

其中UIBezierPath作为小圆点的运动轨迹,CAKeyframeAnimation则用来改变小圆点的座标,在IOS中提供了几种动画运行的效果,很容易实现淡入淡出的效果。

其中,小圆点的运动轨迹应该与外面那个圆环一致,为了方便操作,将小圆点所在的图层作为圆环的子图层就可以不用进行座标转换,如果2个图片层为兄弟关系就需要进行座标转换,这里大家稍微想想就很容易明白,为什么需要座标转换。

 

外面圆环的代码,:只要绘图方法即可,

 

-(void) drawInContext:(CGContextRef)ctx{
    
    
    //画圆
    CGContextSetRGBStrokeColor(ctx,0.52f, 0.76f, 0.07f, 1.0f);
    
    CGContextSetLineWidth(ctx, 2.0);
    
    //    CGContextAddArc(ctx, self.frame.size.width / 2 - 10, self.frame.size.height / 2, 25, 0, PI, 0);
    //
    //    CGContextAddArc(ctx, self.frame.size.width / 2 + 10, self.frame.size.height / 2, 25, 0, PI, 0);
    
    
    /*
     CGContextRef c:上下文
     CGFloat x :x,y圆弧所在圆的中心点坐标
     CGFloat y :x,y圆弧所在圆的中心点坐标
     CGFloat radius :所在圆的半径
     CGFloat startAngle : 圆弧的开始的角度  单位是弧度  0对应的是最右侧的点;
     CGFloat endAngle  : 圆弧的结束角度
     int clockwise : 顺时针(0) 或者 逆时针(1)
     */
    CGContextAddArc(ctx, self.frame.size.width / 2, self.frame.size.height / 2, 25, 0,  2 * PI, 0);
    
    CGContextDrawPath(ctx, kCGPathStroke);
    
    
    //画一个圆点,,将上面的定时器开启可以达到圆点绕圆周运动
//    CGContextSetRGBStrokeColor(ctx,0.12f, 0.26f, 0.07f, 1.0f);
//    CGContextAddArc(ctx,
//                    self.frame.size.width / 2 + cos(self.dAngle * PI / 180) * 25,
//                    self.frame.size.height / 2 + sin(self.dAngle * PI / 180) * 25,
//                    5,
//                    0,
//                    2 * PI,
//                    0);
//    CGContextDrawPath(ctx, kCGPathFillStroke);
    
}

 

 

 

 

 

 

在vc中的测试代码如下:

 

#import "PointMoveByCircleVC.h"
#import "PointMoveByCircleLayer.h"

@interface PointMoveByCircleVC ()

@property(nonatomic,strong) PointMoveByCircleLayer* layer;

@end

@implementation PointMoveByCircleVC

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initView];
}
-(void) initView{

    self.view.backgroundColor  = [UIColor whiteColor];
    
    self.layer = [PointMoveByCircleLayer layer];
    self.layer.dAngle = 0;
    self.layer.frame = CGRectMake(100, 100, 100, 100);
    
    [self.layer setNeedsDisplay];    //写这个方法才会自动触发 drawInContext:的方法
    self.layer.backgroundColor = [UIColor brownColor].CGColor;
    
    [self.view.layer addSublayer:self.layer];
    
    
    UIButton* btnAnim = [[UIButton alloc] initWithFrame:CGRectMake(180, 240, 180, 30)];
    btnAnim.backgroundColor = [UIColor grayColor];
    btnAnim.tag = 13;
    [btnAnim setTitle:@"播放动画" forState:UIControlStateNormal];
    [btnAnim addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnAnim];
}

-(void) onClick:(UIButton*) button{

    switch (button.tag) {
            case 13:{
                
                //[self.layer playAnim];
                
                
                UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
                [bezierPath moveToPoint:CGPointMake(0, 150)];
                [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
                
                //初始化圆点层
                UIBezierPath* path = [[UIBezierPath alloc] init];
                [path addArcWithCenter:CGPointMake(self.layer.frame.size.width / 2, self.layer.frame.size.width / 2)
                                radius:25
                            startAngle:0
                              endAngle:2 * 3.1415926
                             clockwise:1];
                
                
                CALayer *colorLayer = [CALayer layer];
                colorLayer.frame = CGRectMake(0, 0, 5, 5);
                colorLayer.cornerRadius = 2.5;
                colorLayer.position = CGPointMake(self.layer.frame.size.width / 2 + cos(90 * 3.1415926 / 180) * 25,
                                                  self.layer.frame.size.width / 2 + sin(90 * 3.1415926 / 180) * 25);
                
                colorLayer.backgroundColor = [UIColor redColor].CGColor;
                [self.layer addSublayer:colorLayer];
                
                //创建一个帧动画需要 的圆周 路径,这个路径 与外圆圈一一致
                CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
                animation1.keyPath = @"position";
                animation1.path = path.CGPath;
                animation1.duration = 1.0;
                animation1.repeatCount = MAXFLOAT;
                animation1.timingFunction =  [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
                
                
                [colorLayer addAnimation:animation1 forKey:nil];

                
        }
            break;
            
        default:
            break;
    }

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
}



@end

 

  • 补PointMoveByCircleLayer文件:
#import <QuartzCore/QuartzCore.h>

@interface PointMoveByCircleLayer : CALayer

@property(atomic,assign) CGPoint circlePointPos;

@property(nonatomic,assign) double dAngle;

-(void) playAnim;

-(void) stopAnim;

@end
#import "PointMoveByCircleLayer.h"
#import <UIKit/UIKit.h>

#define PI 3.1415926

@implementation PointMoveByCircleLayer

-(instancetype) init{

    if(self = [super init]){
    
        self.dAngle = 0;
    }
    
    return self;
}

-(void) playAnim{

//    NSDate *scheduledTime = [NSDate dateWithTimeIntervalSinceNow:0];
//    NSTimer *timer = [[NSTimer alloc] initWithFireDate:scheduledTime
//                                              interval:0.00000001
//                                                target:self
//                                              selector:@selector(task)
//                                              userInfo:nil
//                                               repeats:YES];
//    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
//    [runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
    
   

}

-(void)task {
    self.dAngle += 1;
    [self setNeedsDisplay];
    
}

-(void) stopAnim{

    
}

-(void) drawInContext:(CGContextRef)ctx{
    
    
    //画圆
    CGContextSetRGBStrokeColor(ctx,0.52f, 0.76f, 0.07f, 1.0f);
    
    CGContextSetLineWidth(ctx, 2.0);
    
    //    CGContextAddArc(ctx, self.frame.size.width / 2 - 10, self.frame.size.height / 2, 25, 0, PI, 0);
    //
    //    CGContextAddArc(ctx, self.frame.size.width / 2 + 10, self.frame.size.height / 2, 25, 0, PI, 0);
    
    
    /*
     CGContextRef c:上下文
     CGFloat x :x,y圆弧所在圆的中心点坐标
     CGFloat y :x,y圆弧所在圆的中心点坐标
     CGFloat radius :所在圆的半径
     CGFloat startAngle : 圆弧的开始的角度  单位是弧度  0对应的是最右侧的点;
     CGFloat endAngle  : 圆弧的结束角度
     int clockwise : 顺时针(0) 或者 逆时针(1)
     */
    CGContextAddArc(ctx, self.frame.size.width / 2, self.frame.size.height / 2, 25, 0,  2 * PI, 0);
    
    CGContextDrawPath(ctx, kCGPathStroke);
    
    
    //画一个圆点,,将上面的定时器开启可以达到圆点绕圆周运动
//    CGContextSetRGBStrokeColor(ctx,0.12f, 0.26f, 0.07f, 1.0f);
//    CGContextAddArc(ctx,
//                    self.frame.size.width / 2 + cos(self.dAngle * PI / 180) * 25,
//                    self.frame.size.height / 2 + sin(self.dAngle * PI / 180) * 25,
//                    5,
//                    0,
//                    2 * PI,
//                    0);
//    CGContextDrawPath(ctx, kCGPathFillStroke);
    
}


@end

 

#import <UIKit/UIKit.h>


/**
 本视图演示一个小圆点在圆弧上做圆周运动
 */
@interface PointMoveByCircleVC : UIViewController

@end
#import "PointMoveByCircleVC.h"
#import "PointMoveByCircleLayer.h"

@interface PointMoveByCircleVC ()

@property(nonatomic,strong) PointMoveByCircleLayer* layer;

@end

@implementation PointMoveByCircleVC

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initView];
}
-(void) initView{

    self.view.backgroundColor  = [UIColor whiteColor];
    
    self.layer = [PointMoveByCircleLayer layer];
    self.layer.dAngle = 0;
    self.layer.frame = CGRectMake(100, 100, 100, 100);
    
    [self.layer setNeedsDisplay];    //写这个方法才会自动触发 drawInContext:的方法
    self.layer.backgroundColor = [UIColor brownColor].CGColor;
    
    [self.view.layer addSublayer:self.layer];
    
    
    UIButton* btnAnim = [[UIButton alloc] initWithFrame:CGRectMake(180, 240, 180, 30)];
    btnAnim.backgroundColor = [UIColor grayColor];
    btnAnim.tag = 13;
    [btnAnim setTitle:@"播放动画" forState:UIControlStateNormal];
    [btnAnim addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnAnim];
}

-(void) onClick:(UIButton*) button{

    switch (button.tag) {
            case 13:{
                
                //[self.layer playAnim];
                
                
//                UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
//                [bezierPath moveToPoint:CGPointMake(0, 150)];
//                [bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
                
                //初始化圆点层路径
                UIBezierPath* path = [[UIBezierPath alloc] init];
                [path addArcWithCenter:CGPointMake(self.layer.frame.size.width / 2, self.layer.frame.size.width / 2)
                                radius:25
                            startAngle:0
                              endAngle:2 * 3.1415926
                             clockwise:1];
                
                
                CALayer *colorLayer = [CALayer layer];
                colorLayer.frame = CGRectMake(0, 0, 5, 5);
                colorLayer.cornerRadius = 2.5;
                colorLayer.position = CGPointMake(self.layer.frame.size.width / 2 + cos(90 * 3.1415926 / 180) * 25,
                                                  self.layer.frame.size.width / 2 + sin(90 * 3.1415926 / 180) * 25);
                
                colorLayer.backgroundColor = [UIColor redColor].CGColor;
                [self.layer addSublayer:colorLayer];
                
                //创建一个帧动画需要 的圆周 路径,这个路径 与外圆圈一一致
                CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
                animation1.keyPath = @"position";
                animation1.path = path.CGPath;
                animation1.duration = 1.0;
                animation1.repeatCount = MAXFLOAT;
                animation1.timingFunction =  [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
                
                
                [colorLayer addAnimation:animation1 forKey:nil];

                
        }
            break;
            
        default:
            break;
    }

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
}



@end

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值