首页 > 学院 > 开发设计 > 正文

ios开发-UI进阶-核心动画-时钟动画小案例

2019-11-14 18:51:20
字体:
来源:转载
供稿:网友

  

  [注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.VEVb.com/hukezhu/

 

  今天使用CALayer的"定位点(锚点)"实现了一个时钟动画,其实就是一个小的时钟,只是实现了功能,没有做出绚丽的效果.使用UIView实现的,其实只是单纯的使用layer也可以实现.主要用到了 Quartz2D画图/ 事件处理/核心动画方面的知识.

  代码不是很多,直接附上源码,注释比较详细,在源码后面再进行解释其中的一些知识点和注意点.

  下图为应用截图,使用gif,没有制作好,见谅哈.[此处图片有一点小问题,时间显示正常,指针处有点问题,代码中修改过来了]

  加了一个显示时间的功能

 

下图为模拟器与电脑时间对比图,和正常时间一样.

  

 

 

  下面附上源代码:

  viewController.m

  这个是最初的源码,界面上没有显示数字时间的功能,把能够显示数字时间的源码放到最后面

  1 //  2 //  ViewController.m  3 //  01-时钟动画time  4 //  5 //  Created by hukezhu on 15/6/12.  6 //  Copyright (c) 2015年 hukezhu. All rights reserved.  7 //  8   9 #import "ViewController.h" 10  11 @interface ViewController () 12 //秒针view 13 @PRoperty(nonatomic,strong)UIView *secondView; 14 //分针view 15 @property(nonatomic,strong)UIView *minView; 16 //时针view 17 @property(nonatomic,strong)UIView *hourView; 18 @end 19  20 @implementation ViewController 21  22 - (void)viewDidLoad { 23     [super viewDidLoad]; 24     //设置背景颜色 25     self.view.backgroundColor = [UIColor greenColor]; 26      27     //创建一个表盘view 28     UIView *clockView = [[UIView alloc]init]; 29     //设置位置 30     clockView.center = self.view.center; 31     //设置大小 32     clockView.layer.bounds = CGRectMake(0, 0, 214, 214); 33      34     //设置显示内容 35     clockView.layer.contents = (__bridge id)([UIImage imageNamed:@"clock1"].CGImage); 36     //设置圆角半径 37     clockView.layer.cornerRadius = 107; 38     //设置裁剪 39     clockView.layer.masksToBounds = YES; 40     //将clockView添加到控制器view中 41     [self.view addSubview:clockView]; 42      43      44      45      46     //创建一个秒针view 47     UIView *secondView = [[UIView alloc]init]; 48     secondView.center = clockView.center; 49     secondView.layer.bounds = CGRectMake(0, 0, 2, 90); 50     secondView.layer.backgroundColor = [UIColor redColor].CGColor; 51     secondView.layer.anchorPoint = CGPointMake(0.5, 1); 52      53     self.secondView = secondView; 54     [self.view addSubview:secondView]; 55      56      57      58     //创建一个分针view 59     UIView *minView = [[UIView alloc]init]; 60     minView.center = clockView.center; 61     minView.layer.bounds = CGRectMake(0, 0, 4, 70); 62     minView.layer.backgroundColor = [UIColor blueColor].CGColor; 63     minView.layer.anchorPoint = CGPointMake(0.5, 1); 64  65     self.minView = minView; 66     [self.view addSubview:minView]; 67      68      69      70     //创建一个时针view 71     UIView *hourView = [[UIView alloc]init]; 72     hourView.center = clockView.center; 73     hourView.layer.bounds = CGRectMake(0, 0, 6, 50); 74     hourView.layer.backgroundColor = [UIColor blackColor].CGColor; 75     hourView.layer.anchorPoint = CGPointMake(0.5, 1); 76      77     self.hourView = hourView; 78     [self.view addSubview:hourView]; 79      80  81     // 开启一个计时器控件 82     //NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(move) userInfo:nil repeats:YES]; 83     //创建一个对象 84     CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(move)]; 85     //启动这个link 86     [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 87 } 88  89  90 - (void)move{ 91  92      93     //1.计算对应的弧度 94     CGFloat angle = M_PI * 2 / 60.0; 95     CGFloat angleMin = M_PI * 2 / 60.0; 96     CGFloat angleHour = M_PI * 2 / 12.0 ; 97      98     //2.获取当前事件 99     NSDate *date = [NSDate date];100     101     //创建一个日历牌对象(NSCalender),通过这个对象才能获取NSDate中的日期时间的每一部分102     NSCalendar *calender = [NSCalendar currentCalendar];103     104     //告诉日历牌对象,需要获取哪些部分的值105     106     //取得当前的秒107     NSInteger secs = [calender component:NSCalendarUnitSecond fromDate:date];108     //取得当前的分109     NSInteger mins = [calender component:NSCalendarUnitMinute fromDate:date];110     //取得当前的时111     NSInteger hours = [calender component:NSCalendarUnitHour fromDate:date];112     113     114     //NSLog(@"%zd,%zd,%zd",hours,mins,secs);//测试用115     116     117     //计算本次旋转应该旋转到的弧度数118     angle = secs *angle;119     angleMin = mins *angleMin + angle/60.0;120     angleHour = hours *angleHour + angleMin/12.0  ;121 122     //让时分秒针旋转123     self.secondView.transform = CGAffineTransformMakeRotation(angle);124     self.minView.transform = CGAffineTransformMakeRotation(angleMin);125     self.hourView.transform = CGAffineTransformMakeRotation(angleHour);126 127 }128 129 @end

 

  当然,这里面的表盘使用的时图片,我们也可以自己画出来,但是此处有图片资源,就直接使用了.(注意需要剪切图片为圆形,当然,有方形的表盘,但是此处是圆形表盘,所以将图片切割成圆形).

  注意:可以使用NSTimer创建一个定时器,但是通过 NSTimer 实现的动画可能造成卡顿、不连贯的情况(NSTimer 不准确),此处使用CADisplayLink.

 

  主要思路就是:

  • 设置view的背景
  • 创建一个表示表盘的view,设置表盘view的大小和位置,在contents属性中设置图片,根据圆角半径的知识,使用masksToBounds进行剪切,将这个view加到控制器的view中
  • 分别创建一个秒针/分针/时针的view,分别设置大小和位置,设置颜色,等属性,分别将view加入到控制器的view中.
  • 创建一个CADisplayLink对象,(CADisplayLink能提供一个周期性调用赋值给它的selector的机制,很像定时器NSTimer)
  • 实现上述CADisplayLink对象中添加的move方法
  • 在move方法中,计算所转的弧度,通过日历牌对象(NSCalender),获取NSDate中的日期时间的每一部分
  • 进行旋转,完毕!

 

 

获取当前系统中的时间的某一部分的方法

 1 //2.获取当前事件 2     NSDate *date = [NSDate date]; 3      4     //创建一个日历牌对象(NSCalender),通过这个对象才能获取NSDate中的日期时间的每一部分 5     NSCalendar *calender = [NSCalendar currentCalendar]; 6      7     //告诉日历牌对象,需要获取哪些部分的值 8      9     //取得当前的秒10     NSInteger secs = [calender component:NSCalendarUnitSecond fromDate:date];11     //取得当前的分12     NSInteger mins = [calender component:NSCalendarUnitMinute fromDate:date];13     //取得当前的时14     NSInteger hours = [calender component:NSCalendarUnitHour fromDate:date];15     16     17     //NSLog(@"%zd,%zd,%zd",hours,mins,secs);//测试用
获取系统中的时间的某一部分的方法

 

知识点:

   注意: 在使用 Quartz2D 绘图的时候, 对绘图上下文的旋转是对坐标系的旋转, 通过 UI 控件的 transform 对控件做旋转是按照 Center 来旋转的。
   注意: 控件的 center 属性, 其实就是对应的 CALayer的 postion。所以控件的 center并不是永远表示控件的中心点。

 

 

 

  

CALayer有2个非常重要的属性:position和anchorPoint

    position:
      @property CGPoint position;
      用来设置CALayer在父层中的位置
      以父层的左上角为原点(0, 0)
 
 
    anchorPoint:
      @property CGPoint anchorPoint;
      称为“定位点”、“锚点”
      决定着CALayer的position属性所指的是哪个点
      以自己的左上角为原点(0, 0)
      它的x、y取值范围都是0~1,默认值为(0.5, 0.5)
 
 

CALayer:

    

    UIView之所以能显示在屏幕上,完全是因为它内部的一个图层
    
    在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个层
     1 @property(nonatomic,readonly,retain) CALayer *layer;  
    
    当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成    了UIView的显示.
 
    CALayer的一些属性
    
//宽度和高度@property CGRect bounds;//位置(默认指中点,具体由anchorPoint决定)@property CGPoint position;//锚点(x,y的范围都是0-1),决定了position的含义@property CGPoint anchorPoint;//背景颜色(CGColorRef类型)@property CGColorRef backgroundColor;//形变属性@property CATransform3D transform;//边框颜色(CGColorRef类型)@property CGColorRef borderColor;//边框宽度@property CGFloat borderWidth;//圆角半径@property CGFloat cornerRadius;//内容(比如设置为图片CGImageRef)@property(retain) id contents;

  

 

  UIView和CALayer的使用区别:

    UIView : 接受和处理系统事件、触摸事件。

    CALayer : 显示内容

  

 

 

界面上有显示时间的label:(主要是一个定时器的功能,1秒刷新一次,显示在label上,实时动态的更新时间)

源码代码:

  1 //  2 //  ViewController.m  3 //  01-时钟动画time  4 //  5 //  Created by hukezhu on 15/6/12.  6 //  Copyright (c) 2015年 hukezhu. All rights reserved.  7 //  8   9 #import "ViewController.h" 10  11 @interface ViewController () 12 //秒针view 13 @property(nonatomic,strong)UIView *secondView; 14 //分针view 15 @property(nonatomic,strong)UIView *minView; 16 //时针view 17 @property(nonatomic,strong)UIView *hourView; 18 //定时器 19 @property(nonatomic,strong)NSTimer *timer; 20 //显示时间的label 21 @property(nonatomic,strong)UILabel *timeLabel; 22 @end 23  24 @implementation ViewController 25  26 - (void)viewDidLoad { 27     [super viewDidLoad]; 28     //设置背景颜色 29     self.view.backgroundColor = [UIColor greenColor]; 30      31     //创建一个表盘view 32     UIView *clockView = [[UIView alloc]init]; 33     //设置位置 34     clockView.center = self.view.center; 35     //设置大小 36     clockView.layer.bounds = CGRectMake(0, 0, 214, 214); 37      38     //设置显示内容 39     clockView.layer.contents = (__bridge id)([UIImage imageNamed:@"clock1"].CGImage); 40     //设置圆角半径 41     clockView.layer.cornerRadius = 107; 42     //设置裁剪 43     clockView.layer.masksToBounds = YES; 44     //将clockView添加到控制器view中 45     [self.view addSubview:clockView]; 46      47      48     //创建一个显示时间的label 49     UILabel *label = [[UILabel alloc]init]; 50    51     //设置位置 52     label.center = CGPointMake(clockView.center.x, clockView.center.y + 130); 53     //设置大小(这样设置不合理,代码很烂,只是单纯的为了实现这个小功能,也没有做自动布局) 54     label.frame = CGRectMake(clockView.center.x-60, clockView.center.y + 150, 100, 44); 55     //设置背景颜色 56     label.backgroundColor = [UIColor whiteColor]; 57     //设置字体颜色 58     label.textColor = [UIColor redColor]; 59     //设置字体居中 60     label.textAlignment = NSTextAlignmentCenter; 61     //设置字体大小 62     label.font = [UIFont systemFontOfSize:20]; 63      64     self.timeLabel = label; 65     [self.view addSubview:label]; 66      67      68      69      70      71     //创建一个秒针view 72     UIView *secondView = [[UIView alloc]init]; 73     secondView.center = clockView.center; 74     secondView.layer.bounds = CGRectMake(0, 0, 2, 90); 75     secondView.layer.backgroundColor = [UIColor redColor].CGColor; 76     secondView.layer.anchorPoint = CGPointMake(0.5, 1); 77      78     self.secondView = secondView; 79     [self.view addSubview:secondView]; 80      81      82      83     //创建一个分针view 84     UIView *minView = [[UIView alloc]init]; 85     minView.center = clockView.center; 86     minView.layer.bounds = CGRectMake(0, 0, 4, 70); 87     minView.layer.backgroundColor = [UIColor blueColor].CGColor; 88     minView.layer.anchorPoint = CGPointMake(0.5, 1); 89  90     self.minView = minView; 91     [self.view addSubview:minView]; 92      93      94      95     //创建一个时针view 96     UIView *hourView = [[UIView alloc]init]; 97     hourView.center = clockView.center; 98     hourView.layer.bounds = CGRectMake(0, 0, 6, 50); 99     hourView.layer.backgroundColor = [UIColor blackColor].CGColor;100     hourView.layer.anchorPoint = CGPointMake(0.5, 1);101     102     self.hourView = hourView;103     [self.view addSubview:hourView];104     105 106     // 开启一个计时器控件107     //NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(move) userInfo:nil repeats:YES];108     //创建一个对象109     CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(move)];110     //启动这个link111     [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];112     113     114     _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timeRun) userInfo:nil repeats:YES];115 }116 117 - (void)timeRun{118     119     NSDateFormatter *fmt = [[NSDateFormatter alloc] init];120     121     [fmt setDateFormat:@" HH:mm:ss"];122     123     NSString *time = [fmt stringFromDate:[NSDate date]];124     125     [self.timeLabel setText:time];126     127     128 129 }130 131 132 133 - (void)move{134 135     136     //1.计算对应的弧度137     CGFloat angle = M_PI * 2 / 60.0;138     CGFloat angleMin = M_PI * 2 / 60.0;139     CGFloat angleHour = M_PI * 2 / 12.0 ;140     141     //2.获取当前事件142     NSDate *date = [NSDate date];143     144     //创建一个日历牌对象(NSCalender),通过这个对象才能获取NSDate中的日期时间的每一部分145     NSCalendar *calender = [NSCalendar currentCalendar];146     147     //告诉日历牌对象,需要获取哪些部分的值148     149     //取得当前的秒150     NSInteger secs = [calender component:NSCalendarUnitSecond fromDate:date];151     //取得当前的分152     NSInteger mins = [calender component:NSCalendarUnitMinute fromDate:date];153     //取得当前的时154     NSInteger hours = [calender component:NSCalendarUnitHour fromDate:date];155     156     157     //NSLog(@"%zd,%zd,%zd",hours,mins,secs);//测试用158     159     160     //计算本次旋转应该旋转到的弧度数161     angle = secs *angle;162     angleMin = mins *angleMin + angle/60.0;163     angleHour = hours *angleHour + angleMin/12.0  ;164 165     //让时分秒针旋转166     self.secondView.transform = CGAffineTransformMakeRotation(angle);167     self.minView.transform = CGAffineTransformMakeRotation(angleMin);168     self.hourView.transform = CGAffineTransformMakeRotation(angleHour);169 170 }171 172 @end

这段代码不是很规范,有许多需要优化的地方,只是单纯的实现了这个功能,请勿喷~~~~~~~~

 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表