zoukankan      html  css  js  c++  java
  • ios开发-UI进阶-核心动画-时钟动画小案例

      

      [注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.cnblogs.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     //启动这个link
    111     [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

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

     
  • 相关阅读:
    反射之初认识
    面向对象(上)练习一 改进:调用方法
    关于php中id设置自增后不连续的问题
    由于定界符引出的格式错误问题
    PHP 关于timezone问题
    2016.4.29 园子第一天,希望所有的坚持都有所收获
    递归调用
    动手动脑
    界面实验任务
    课程作业02
  • 原文地址:https://www.cnblogs.com/hukezhu/p/4572374.html
Copyright © 2011-2022 走看看