动画iOS 动画iOS 特效功能

司机王教你用CALayer写一个iOS时钟效果

2016-03-12  本文已影响2052人  司机王

纯属原创,转载请标明出处,谢谢

首先我们先看一下需求

按照MAC的系统时钟仿照写一个类似的时钟效果


然后我们着手分析一个这个如何实现

首先这个不需要和用户有任何交互,所以我们推荐使用CALayer隐式动画去完成

然后我们让设计人员先画出一个表盘给我们,设置他的长宽都为200

其次,我们就要通过需求来描述CALayer的anchorPoint与position点在哪里

至于这两个点是什么(也就是“锚点”),彻底理解position与anchorPoint - yongyinmg的专栏 - 博客频道 - CSDN.NET,这篇文章说的很清楚了,这里就不跟大家解释

我们可以看到,所有的layer都是基于锚点去旋转的,也就是表盘的中心点,那么position属性也就是表盘的长宽的一半,由于anchorPoint的X,Y属性取值范围是0-1之间,以秒针举例,如果我们想让秒针站立在表盘中上,那么秒针的X即为0.5,Y为1

在设置下秒针的bound,宽度为1,长度为表盘的半径-20

这样我们可以轻松的将秒针针添加到表盘上

    CALayer * secondL = [CALayer layer];
    
    secondL.backgroundColor = [UIColor redColor].CGColor ;

    // 设置锚点
    
    secondL.anchorPoint = CGPointMake(0.5, 1);
    
    secondL.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    secondL.bounds = CGRectMake(0, 0, 1, kClockW * 0.5 - 20);
    

    [_clockView.layer addSublayer:secondL];

    _secondLayer = secondL;

同理,时针和分针也是一样,只不过长度和颜色,圆角不一样

   CALayer * layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor ;
    
    // 设置锚点
    
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 20);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _mintueLayer = layer;

     CALayer * layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor ;
    
    // 设置锚点
    
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 40);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _hourLayer = layer;

这里一定要注意的是添加顺序,一般来讲秒针在最上层,所以秒针的layer是最后添加的

现在UI层我们已经添加好了,接下来就该考虑如何让时钟动起来了

让时钟动起来,我们先要知道时分秒他们在表盘上所谓转动的角度

通过小学运算可以得知,秒针在一秒钟内在表盘里转动的度数是6度(一个圆形是360度,360除以60),拿现在的系统的秒数*6就是现在秒针的具体度数

分针在一分钟内在表盘转动的度数也是6度

而时针呢,一小时时针变化为360除以12等于30度,但是有个问题,常理知,时钟并不是只有在分针转到12点的时候才变化,它表盘里也会随着分针的变化而变化(比如说1:30,时针不可能只还停留在1这个位置,等到2:00的时候才突然变化)所以这个角度还需要加上分针对它的变化。这个怎么算呢,拿30度除以60现在的系统分钟数就可以得到了,也就是0.5现在的分钟数就是时钟在以分钟作单位时转动的度数

30*系统小时+0.5*系统分钟

由于这些都是不可变化的,我们来抽成宏

// 1秒6度(秒针)

#define perSecondA 6

// 1分钟6度(分针)

#define perMintueA 6

// 1小时30度(时针)

#define perHourA 30

// 每分钟时针转(30 / 60 °)

#define perMinHourA 0.5

有了这些角度之后,剩下的就很好做了,我们在viewDidLoad的里添加一个定时器

 [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];

然后在这个timeChange方法里,设置时分秒的旋转形变就可以了,这里注意,CATransform3DMakeRotation这个接受的弧度而不是角度,我们再抽出一个宏来将角度转化为弧度

#define angle2radion(angle) ((angle) / 180.0 * M_PI)
- (void)timeChange{
    
    // 获取当前系统时间
    
    NSCalendar * calender = [NSCalendar currentCalendar];
    
    NSDateComponents * cmp = [calender components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour  fromDate:[NSDate date]];
    
    CGFloat second = cmp.second;
    
    CGFloat secondA = (second * perSecondA) ;
    
    NSInteger minute = cmp.minute;
    
    CGFloat mintuteA = minute * perMintueA ;
    
    NSInteger hour = cmp.hour;
    
    CGFloat hourA = hour * perHourA  + minute * perMinHourA;
    
    _secondLayer.transform = CATransform3DMakeRotation(angle2radion(secondA), 0, 0, 1);

    _mintueLayer.transform = CATransform3DMakeRotation(angle2radion(mintuteA), 0, 0, 1);
    
    _hourLayer.transform = CATransform3DMakeRotation(angle2radion(hourA), 0, 0, 1);
}

做到这里,基本上已经大功告成,让我们运行一下

时钟已经随着系统时间转了起来,还可以在修改一些别的样式,到时候就看开发者如何发挥了

本Dome的Github地址
https://github.com/DriverWang/YCClock

上一篇下一篇

猜你喜欢

热点阅读