时钟动画

作者: iLees | 来源:发表于2016-07-07 11:32 被阅读93次

    最近项目中用到了一些动画效果,研究的过程中发现挺有意思,那就分享一下喽!
    首先看一下素材:

    下面是实现后的效果:


    代码如下:

    #import <UIKit/UIKit.h>
    
    @interface LSZClockView : UIView
    
    - (instancetype)initWithFrame:(CGRect)frame imageName:(NSString *)imageName;
    
    @end
    
    #import "LSZClockView.h"
    
    #define kAngleToRadion(angle) ((angle) / 180.0 * M_PI)
    
    @interface LSZClockView()
    
    /** 背景图片 */
    @property (nonatomic, copy) NSString *imageName;
    /** 时针 */
    @property (nonatomic, strong) CALayer *hourLayer;
    /** 分针 */
    @property (nonatomic, strong) CALayer *minuteLayer;
    /** 秒针 */
    @property (nonatomic, strong) CALayer *secondLayer;
    /** Timer */
    @property (nonatomic, strong) NSTimer *timer;
    /** 日期组 */
    @property (nonatomic, strong) NSDateComponents *dateComponents;
    
    @end
    
    @implementation LSZClockView
    
    #pragma mark - Life Circle
    
    - (void)dealloc {
        if (_timer) {
            [_timer invalidate];
            _timer = nil;
        }
    }
    
    - (instancetype)initWithFrame:(CGRect)frame imageName:(NSString *)imageName {
        if (self = [super initWithFrame:frame]) {
            self.imageName = imageName;
            [self buildView];
        }
        return self;
    }
    
    - (void)buildView {
        // 设置时钟背景图片
        @autoreleasepool {
            self.layer.contents = (__bridge id)[UIImage imageNamed:self.imageName].CGImage;
        }
        // 设置timer
        
    }
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        // 延迟添加各layer
        [self.layer addSublayer:self.hourLayer];
        [self.layer addSublayer:self.minuteLayer];
        [self.layer addSublayer:self.secondLayer];
        self.secondLayer.cornerRadius = 0;
        // 开启timer 需关闭动画
    //    if (self.timer.valid) {}
        
    }
    
    #pragma mark - Tool Method
    
    - (CALayer *)layerWithBackgroundColor:(UIColor *)color size:(CGSize)size {
        CALayer *layer = [CALayer layer];
        // 设置背景色
        layer.backgroundColor = color.CGColor;
        // 设置锚点
        layer.anchorPoint = CGPointMake(0.5, 1);
        // 设置为 self 中心
        layer.position = CGPointMake(self.frame.size.width * 0.5, self.frame.size.height * 0.5);
        // 设置size
        layer.bounds = CGRectMake(0, 0, size.width, size.height);
        // 设置圆角
        layer.cornerRadius = 2;
        return layer;
    }
    
    - (CABasicAnimation *)animationWithAngle:(CGFloat)angle duration:(CFTimeInterval)duration{
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        animation.repeatCount = HUGE_VALF;
        animation.duration = duration;
        animation.removedOnCompletion = NO;
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        animation.fromValue = @(angle * M_PI / 180);
        animation.byValue = @(2 * M_PI);
        return animation;
    }
    
    #pragma mark - Event
    
    - (void)timerInterval {
        // 获取当前时分秒数据
        NSCalendar *calendar = [NSCalendar currentCalendar];
        NSDateComponents *components = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:[NSDate date]];
        NSInteger hour = components.hour;
        NSInteger minute = components.minute;
        NSInteger second = components.second;
        // 时针角度
        CGFloat hourUnitAngle = 1.0 / 12.0 * 360;
        CGFloat hourAngle = hour * hourUnitAngle + minute * 1.0  / 60 * hourUnitAngle;
        self.hourLayer.transform = CATransform3DMakeRotation(kAngleToRadion(hourAngle), 0, 0, 1);
        // 分针角度
        CGFloat minuteAngle = minute * 1.0 / 60.0 * 360;
        self.minuteLayer.transform = CATransform3DMakeRotation(kAngleToRadion(minuteAngle), 0, 0, 1);
        // 秒针角度
        CGFloat secondAngle = second * 1.0 / 60.0 * 360;
        self.secondLayer.transform = CATransform3DMakeRotation(kAngleToRadion(secondAngle), 0, 0, 1);
    }
    
    #pragma mark - Property
    
    - (CALayer *)hourLayer {
        if (!_hourLayer) {
            _hourLayer = [self layerWithBackgroundColor:[UIColor blackColor] size:CGSizeMake(3, self.frame.size.height * 0.5 - 40)];
            CGFloat hourUnitAngle = 1.0 / 12.0 * 360;
            CGFloat hourAngle = self.dateComponents.hour * hourUnitAngle + self.dateComponents.minute * 1.0  / 60 * hourUnitAngle;
            [_hourLayer addAnimation:[self animationWithAngle:hourAngle duration:60 * 60 * 12]  forKey:@"HourAnimationKey"];
        }
        return _hourLayer;
    }
    
    - (CALayer *)minuteLayer {
        if (!_minuteLayer) {
            _minuteLayer = [self layerWithBackgroundColor:[UIColor blackColor] size:CGSizeMake(3, self.frame.size.height * 0.5 - 25)];
            CGFloat minuteAngle = self.dateComponents.minute * 1.0 / 60.0 * 360;
            [_minuteLayer addAnimation:[self animationWithAngle:minuteAngle duration:60 * 60]  forKey:@"MinuteAnimationKey"];
        }
        return _minuteLayer;
    }
    
    - (CALayer *)secondLayer {
        if (!_secondLayer) {
            _secondLayer = [self layerWithBackgroundColor:[UIColor blackColor] size:CGSizeMake(1, self.frame.size.height * 0.5 - 20)];
            CGFloat secondAngle = self.dateComponents.second * 1.0 / 60.0 * 360;
            [_secondLayer addAnimation:[self animationWithAngle:secondAngle duration:60]  forKey:@"SecondAnimationKey"];
        }
        return _secondLayer;
    }
    
    - (NSTimer *)timer {
        if (!_timer) {
            _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerInterval) userInfo:nil repeats:YES];
            [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
            [self timerInterval];
        }
        return _timer;
    }
    
    - (NSDateComponents *)dateComponents {
        if (!_dateComponents) {
            NSCalendar *calendar = [NSCalendar currentCalendar];
            _dateComponents = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:[NSDate date]];
        }
        return _dateComponents;
    }
    

    这么调用的:

    LSZClockView *clockView = [[LSZClockView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width * 0.5 - 100, 50, 200, 200) imageName:@"clock"];
        [self.view addSubview:clockView];
    

    说明一下:
    1、代码中包含了用Timer 和 CABasicAnimation两种方式的实现;
    2、运行后会发现CALayer会有虚化现象,目前尝试过设置shouldRasterize,但这种方式在有动画效果或calayer不断形变的时候会有缓存问题,果断放弃。目前能够想到的是自己去画线,有兴趣的同学可以试试。

    相关文章

      网友评论

        本文标题:时钟动画

        本文链接:https://www.haomeiwen.com/subject/thhljttx.html