• ios开发核心动画三:隐式动画与时钟效果


    一:隐式动画

    #import "ViewController.h"
    
    @interface ViewController ()
    
    /** <#注释#> */
    @property (nonatomic, weak)  CALayer *layer;
    @property (weak, nonatomic) IBOutlet UIView *redView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        
        
        CALayer *layer = [CALayer layer];
        layer.backgroundColor = [UIColor redColor].CGColor;
        layer.frame = CGRectMake(50, 50, 100, 100);
        self.layer = layer;
        [self.view.layer addSublayer:layer];
        
        
    }
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        //只有非根层才有隐式动画,(自己手动创建的图片)
        [CATransaction begin];
        [CATransaction setDisableActions:NO];//此属性可设置关掉隐士动画
        [CATransaction setAnimationDuration:5];
        self.layer.backgroundColor = [UIColor greenColor].CGColor;
        [CATransaction commit];
        
        self.layer.bounds = CGRectMake(0, 0, 90, 90);
        self.layer.backgroundColor = [UIColor greenColor].CGColor;
        self.layer.position = CGPointMake(100, 400);
        
        
        self.redView.layer.position = CGPointMake(300, 400);
        self.redView.layer.bounds = CGRectMake(0, 0, 100, 100);
        self.redView.layer.backgroundColor = [UIColor greenColor].CGColor;
        
    }
    
    
    @end

    什么是隐式动画?

    了解什么是隐式动画前,要先了解是什么根层和非根层.

    根层:UIView内部自动关联着的那个layer我们称它是根层.

    非根层:自己手动创建的层,称为非根层.

    隐式动画就是当对非根层的部分属性进行修改时, 它会自动的产生一些动画的效果.

    我们称这个默认产生的动画为隐式动画.

    如何取消隐式动画?

    首先要了解动画底层是怎么做的.动画的底层是包装成一个事务来进行的.

    什么是事务?

    很多操作绑定在一起,当这些操作执行完毕后,才去执行下一个操作.

    开启事务

    [CATransaction begin];

    设置事务没有动画

    [CATransaction setDisableActions:YES];

    设置动画执行的时长

    [CATransaction setAnimationDuration:2];

     提交事务

     [CATransaction commit];

    二:时钟效果:

    效果如图:

    #import "ViewController.h"
    
    //每一秒旋转的度数
    #define perSecA 6
    
    //每一分旋转的度数
    #define perMinA 6
    
    //每一小时旋转的度数
    #define perHourA 30
    
    //每一分,时针旋转的度数
    #define perMinHour 0.5
    
    
    #define angle2Rad(angle) ((angle) / 180.0 * M_PI)
    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UIImageView *colockView;
    
    /** 当前的秒针 */
    @property (nonatomic, weak)   CALayer *secL;
    /** 当前的分针 */
    @property (nonatomic, weak)   CALayer *minL;
    /** 当前的针针 */
    @property (nonatomic, weak)   CALayer *hourL;
    
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //添加时针
        [self setHour];
        
        //添加分针
        [self setMin];
        //添加秒针
        [self setSec];
        
        
        //添加定时器:scheduledTimerWithTimeInterval不用加到runLoop,因为已经默认添加到了runLoop
        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
        //添加的定时器不会立即执行,而是过一秒才会执行,此时可以调用定时器的fire方法,立即执行,也可以手动调用定时器的方法
        [self timeChange];
    }
    
    //第一称调用一次
    - (void)timeChange {
        
        
        
        NSCalendar *cal = [NSCalendar currentCalendar];
        //components:日历的组件,年,月,日 ,时,分,秒.
        //fromDate:从什么时间开始获取
        NSDateComponents *cmp = [cal components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour  fromDate:[NSDate date]];
        //获取当前多少秒
        NSInteger curSec = cmp.second + 1;
        
        
        //秒针开始旋转
        //计算秒针当前旋转的角度.
        //angle  = 当前多少秒 * 每一秒旋转多少度.
        /**
         *    CATransform3DMakeRotation:3D旋转:1:必须是在layear层才能进行3D旋转,用transform,旋转的角度为弧度制,2:#define angle2Rad(angle) ((angle) / 180.0 * M_PI) 3:分xyz轴,
         */
        CGFloat secA = curSec * perSecA;
        self.secL.transform = CATransform3DMakeRotation(angle2Rad(secA), 0, 0, 1);
        
        
        //获取当前多少秒
        NSInteger curMin = cmp.minute;
        NSLog(@"%ld",curMin);
        //分针开始旋转
        //计算分针当前旋转的角度.
        //angle  = 当前多少分 * 每一分旋转多少度.
        CGFloat minA = curMin * perMinA;
        self.minL.transform = CATransform3DMakeRotation(angle2Rad(minA), 0, 0, 1);
        
        //获取当前是多少小时
        NSInteger curHour = cmp.hour;
        NSLog(@"%ld",curMin);
        //分针开始旋转
        //计算分针当前旋转的角度.
        //angle  = 当前多少小时 * 每一小时旋转多少度.
        CGFloat hourA = curHour * perHourA + curMin * perMinHour;
        self.hourL.transform = CATransform3DMakeRotation(angle2Rad(hourA), 0, 0, 1);
        
        
    }
    
    /**
     *  1:搭建时针秒针分针的UI效果:1:UIView和CALayear是一样的效果,但是UIView比CALyear多了一个处理点击事件,则CALyear相对于UIView来说更加轻量级,更加高效 2:非根层的layear也就是自己创建的layear都存在隐士动画,要关闭隐式动画,用动画事物CATransaction去关闭:
        开启事务
     
        [CATransaction begin];
     
        设置事务没有动画
     
        [CATransaction setDisableActions:YES];
     
        设置动画执行的时长
     
        [CATransaction setAnimationDuration:2];
     
        提交事务
     
        [CATransaction commit];
     
      3:无论是旋转,缩放都是绕着锚点进行的.也就是默认情况下是绕着中心点center进行的。所以要改变其绕着最后的节点旋转,需要先定义好layear的position,在定义锚点,最后的效果是锚点与point点重合。position的位置为表盘的中心点,锚点的默认位置为0.5 ,0.5,修改表盘的锚点位置让锚点与position点重合,这样旋转的时候就会绕着锚点旋转。再把此layear添加到表盘的layear上。
     *
     *
     */
    
    //添加秒针
    //无论是旋转,缩放都是绕着锚点进行的.
    - (void)setSec {
        
        CALayer *secL = [CALayer layer];
        secL.bounds = CGRectMake(0, 0, 1, 80);
        secL.backgroundColor = [UIColor redColor].CGColor;
        secL.anchorPoint = CGPointMake(0.5, 1);
        secL.position = CGPointMake(self.colockView.bounds.size.width * 0.5, self.colockView.bounds.size.height * 0.5);
        [self.colockView.layer addSublayer:secL];
        self.secL = secL;
        
    }
    
    //添加分针
    - (void)setMin {
        
        CALayer *minL = [CALayer layer];
        minL.bounds = CGRectMake(0, 0, 3, 70);
        minL.backgroundColor = [UIColor blackColor].CGColor;
        minL.anchorPoint = CGPointMake(0.5, 1);
        minL.cornerRadius = 1.5;
        minL.position = CGPointMake(self.colockView.bounds.size.width * 0.5, self.colockView.bounds.size.height * 0.5);
        [self.colockView.layer addSublayer:minL];
        self.minL = minL;
        
    }
    
    //时针
    - (void)setHour {
        
        CALayer *hourL = [CALayer layer];
        hourL.bounds = CGRectMake(0, 0, 3, 50);
        hourL.backgroundColor = [UIColor blackColor].CGColor;
        hourL.anchorPoint = CGPointMake(0.5, 1);
        hourL.cornerRadius = 1.5;
        hourL.position = CGPointMake(self.colockView.bounds.size.width * 0.5, self.colockView.bounds.size.height * 0.5);
        [self.colockView.layer addSublayer:hourL];
        self.hourL = hourL;
        
    }
    
    
    
    
    //-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //
    //    //所有旋转,缩放,都是绕着锚点进行.
    //    self.secL.transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
    //}
    
    @end

    1.搭建界面.

    分析界面.

    界面上时针,分针,秒针不需要与用户进行交互.所以都可以使用layer方式来做.

    做之前要观察时针在做什么效果.

    是根据当前的时间,绕着表盘的中心点进行旋转.

    要了解一个非常重要的知识点.无论是旋转,缩放它都是绕着锚点.进行的.

    要想让时针,分针,称针显示的中间,还要绕着中心点进行旋转.

    那就要设置它的position和anchorPoint两个属性.

    创建秒针

        CALayer *layer = [CALayer layer];

        _secLayer = layer;

        layer.bounds = CGRectMake(0, 0, 1, 80);

        layer.anchorPoint = CGPointMake(0.5, 1);

        layer.position = CGPointMake(_clockView.bounds.size.width * 0.5, _clockView.bounds.size.height * 0.5);

        layer.backgroundColor = [UIColor redColor].CGColor;

        [_clockView.layer addSublayer:layer];

       

       

    2.让秒针开始旋转.

     

    让秒针旋转.所以要计算当前的旋转度是多少?

    当前的旋转角度为:当前的时间 * 每秒旋转多少度.

     

    计算每一秒旋转多少度.

    60秒转一圈360度

    360 除以60就是每一秒转多少度.每秒转6度.

     

    获取当前的时间

    创建日历类

            NSCalendar *calendar = [NSCalendar currentCalendar];

            把日历类转换成一个日期组件

            日期组件(年,月,日,时,分,秒)

            component:日期组件有哪些东西组成,他是一个枚举,里面有年月日时分秒

            fromDate:当前的日期

            NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond

                fromDate:[NSDate date]];

                

            我们的秒就是保存在日期组件里面,它里面提供了很多get方法.

            NSInteger second = cmp.second;

             

            那么当前秒针旋转的角度就是

            当前的秒数乘以每秒转多少度.

            second * perSecA 

            还得要把角度转换成弧度.

            

            因为下面分针,时针也得要用到, 就把它抽出一个速参数的宏.

            #define angle2Rad(angle) ((angle) / 180.0 * M_PI)

            

            让它每隔一秒旋转一次.所以添加一个定时器.

            每个一秒就调用,旋转秒针

             - (void)timeChange{

             获取当前的秒数

             创建日历类

             NSCalendar *calendar = [NSCalendar currentCalendar];

             把日历类转换成一个日期组件

             日期组件(年,月,日,时,分,秒)

             component:日期组件有哪些东西组成,他是一个枚举,里面有年月日时分秒

             fromDate:当前的日期

             NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond 

                 fromDate:[NSDate date]];

             我们的秒就是保存在日期组件里面,它里面提供了很多get方法.

             NSInteger second = cmp.second;

             秒针旋转多少度.

             CGFloat angel = angle2Rad(second * perSecA);

             旋转秒针

             self.secondL.transform = CATransform3DMakeRotation(angel, 0, 0, 1);

             }

            运行发现他会一下只就调到某一个时间才开始旋转

            一开始的时候就要来到这个方法,获取当前的秒数把它定位好.

            要在添加定时器之后就调用一次timeChange方法.

            

     

    3.添加分针

     

    快速拷贝一下,然后添加一个分针成员属性.

            修改宽度,修改颜色

            也得要让它旋转,

            要算出每分钟转多少度

            转60分钟刚好是一圈

            所以每一分钟也是转6度.

            

            获取当前多少分?

            同样是在日期组件里面获得

            里面有左移符号,右移符号.他就可以用一个并运算

            现在同时让他支持秒数和分 后面直接加上一个 |

             NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond | 

             NSCalendarUnitMinute 

             fromDate:[NSDate date]];

             

            CGFloat minueteAngel = angle2Rad(minute * perMinuteA);

            self.minueL.transform = CATransform3DMakeRotation(minueteAngel, 0, 0, 1);

     

    4.添加时针

     

      同样复制之前的,添加一个小时属性

             小时转多少度

             当前是多少小时,再计算先每一小时转多少度.

             12个小时转一圈. 360除以12,每小时转30度

             时针旋转多少度

             CGFloat hourAngel = angle2Rad(hour * perHourA);

             旋转时针

             self.hourL.transform = CATransform3DMakeRotation(hourAngel, 0, 0, 1);

                

            直接这样写会有问题

            就是没转一分钟,小时也会移动一点点

            接下来要算出,每一分钟,小时要转多少度

            60分钟一小时.一小时转30度.

            30 除以60,就是每一分钟,时针转多少度.0.5

            时针旋转多少度

            CGFloat hourAngel = angle2Rad(hour * perHourA + minute * perMinuteHourA);

            旋转时针

            self.hourL.transform = CATransform3DMakeRotation(hourAngel, 0, 0, 1);

     

  • 相关阅读:
    DOM基础
    9个实用的Javascript代码高亮脚本
    去掉超链接虚线框去掉chrome浏览器中input或textarea在得到焦点时出现黄色边框和取消可以拖动大小
    我的Gvim配置文件
    收集的一些有关UED的团队和个人博客
    JS函数:返回下一个元素节点而不是下一个节点
    分享一款图片导航效果 Animated Slideshow Navigation
    原生javascript写的Tab菜单(函数版)
    单个select语句实现MySQL查询统计次数
    mysql 语句case when
  • 原文地址:https://www.cnblogs.com/cqb-learner/p/5838974.html
Copyright © 2020-2023  润新知