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);

 

 

posted on 2016-09-04 12:02  Hello_IOS  阅读(812)  评论(0编辑  收藏  举报

导航