[学习笔记]_核心动画

出处:小码哥大神班5期


CALayer的基本操作


1.CALayer的简介

CALayer又称做层,每个view内部都有一个layer这样的属性。UIView因为CALayer层,才具有显示功能。我们可以通过操作CALayer对象,对UIView进行一些外观属性的调整。比如设置阴影、圆角、边框等。

2.操作layer改变UIView的外观

    //设置圆角
    view.layer.cornerRadius = 5;
    
    //设置阴影不透明度,默认图层是有阴影的,只不过是透明的
    view.layer.shadowOpacity = 1;
    //设置阴影圆角
    view.layer.shadowRadius = 10;
    //设置阴影颜色
    view.layer.shadowColor = [UIColor grayColor].CGColor;
    //设置阴影位置的偏移量
    view.layer.shadowOffset = CGSizeMake(10, 10);

    //设置边框
    view.layer.borderWidth = 2;
    view.layer.borderColor = [UIColor blackColor].CGColor;

效果:

[学习笔记]_核心动画_第1张图片
CALayer操作,改变view的外观.png

3.操作layer改变UIImageViewView的外观

    //设置图片边框
    imageV.layer.borderWidth = 2;
    imageV.layer.borderColor = [UIColor orangeColor].CGColor;
    //设置图片圆角半径
    imageV.layer.cornerRadius = 100;
    //裁剪超出区域部分的的图片
    imageV.layer.masksToBounds = YES;
    /*
     注:UIImageView当中的ImageView并不是直接添加在层上面的,这是添加在layer当中的
     contents里,我们设置所有属性只作用在层上面,对contents里面的东西并不起作用,所有以我们
     看不到图片有圆角的效果,可以把maskToBounds这个属性设为yes,
     当设为yes,就会把超过根层以外的东西都给裁剪掉。
     */

效果:


[学习笔记]_核心动画_第2张图片
CALayer操作imageV.png

4.layer的CATransform3D属性

只有旋转的时候才可以看出3d效果
可以通过kvc的方式进行设置属性,
但是CATransform3DMakeRotation的值是一个结构体,所以用kvc进行设置时要把结构体转成对象

NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
      [_imageView.layer setValue:value forKeyPath:@"transform.scale"];

什么时候用kvc

  • 当需要做一些快速缩放,平移,二维的旋转是用kvc.
    后面forKeyPath属性值不是乱写的,苹果文档当中给了相关的属性。
//平移    
[UIView animateWithDuration:1 animations:^{
        self.imageV.layer.transform = CATransform3DMakeTranslation(-50, -100, 1);
    }];    

//缩放
    [UIView animateWithDuration:1 animations:^{
        [self.imageV.layer setValue:@(0.5) forKeyPath:@"transform.scale"];
    }];


//旋转

    [UIView animateWithDuration:1 animations:^{
        self.imageV.layer.transform =CATransform3DMakeRotation(M_PI , 1, 0, 0);  
    }];

效果:

旋转平移缩放.gif

自定义CALayer


1.如何自定义layer

自定义CALayer的方式和创建UIView的方式非常相似。

CALayer *layer = [CALayer layer];
     layer.frame = CGRectMake(50, 50, 100, 100);
     layer.backgroundColor = [UIColor redColor].CGColor;
     [self.view.layer addSublayer:layer];
//给layer设置图片
layer.contents = (id)[UIImage imageNamed:@"阿狸头像"].CGImage;

2.关于CALayer的疑惑

  • 为什么要使用CGImageRef、CGColorRef

为了保证可移植性,QuartzCore不能使用UIImage、UIColor只能使用CGImageRef、CGColorRef

  • UIView和CALayer都能够显示图形,该怎么选择?

对比CALayer,UIView多了一个事件处理功能。也就是说CALayer不能处理用户的触摸事件,而UIView可以。所以如果显示的东西需要跟用户进行交互的话,用UIView;如果不需要的话用CALayer;因为CALayer的性能会高一些,因此它少了事件处理功能,更加轻量级。


3.position和anchorpoint

position和anchorpoint是CALayer的两个属性。
以前修改一个空间的位置都是通过frame的方式进行修改。现在利用CALayer的position和anchorpoint也能够修改控件的位置
position:它是用来设置当前的layer在父控件当中的位置的.所以它的坐标原点是以父控件的左上角为坐标原点; anchorpoint:它是决定CALayer身上哪一个会在position属性所指的位置,anchorpoint是以当前的layer左上角为原点;它的取值范围是0~1,默认值是(0.5,0.5)的位置,anchorpoint又称锚点,就是把锚点定到position所指的位置
两者结合使用:想要修改某个控件的位置,可以先设置它的position点,设置完毕后,在设置layer身上的anchorpoint锚点。


4.隐式动画

  • 什么是隐式动画

了解什么是隐式动画之前,要先了解什么是根曾和非根层。
根层:UIView内部自动关联着的那个layer,我们称着为根层。
非根层:自己手动创建的层,称着为非根层。
隐式动画就是当非根层的部分属性进行修改时,自动产生的一些动画效果。

  • 如何取消隐式动画?

首先要了解动画底层是怎么做的,动画的底层是包装成一个事物来进行的。
什么是事务?
很多操作绑定在一起,当这些操作执行完毕后,才去执行下一个操作。

//开启事务
[CATransaction begin];
//设置事务没有动画
[CATransaction setDisableActions:yes];
//设置动画执行时长
[CATransaction setAnimationDuration:2];
//提交事务
[CATransaction commit];

6.CABasicAnimation基础核心动画

核心动画是作用在层上面的。
动画的本质是改变图层的某一个属性。
CABasicAnimation *anim = [CABasicAnimation animation];
图层有哪些属性,这里才能写哪些属性。
anim.keyPath = @"transform.scale";
anim.toValue = @0.5;
//告诉动画完成时不要移除
anim.removedOnCompletion = NO;
//保存动画最前面的效果
anim.fillMode = kCAFillModeForwards;
//把动画添加到层上面
[view.layer addAnimation:anim forkey:nil];

7.UIView与核心动画的对比

  • UIView和核心动画的区别

核心动画只能添加到CALayer
核心动画一切都是假象,并不会改变真实的值。

  • 什么时候使用UIView动画

如果需要与用户交互就使用UIView动画。
不需要就使用核心动画

  • 什么场景使用核心动画最多

在转场动画中,核心动画的类型比较多。
根据一个路径做动画,只能用核心动画(帧动画)
动画组:同时做多个动画


练习项目

时钟效果

[学习笔记]_核心动画_第3张图片
时钟效果.gif

代码:

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *clockView;

//秒针的层
@property (weak,nonatomic) CALayer *secondLayer;

//分针的层
@property (weak,nonatomic) CALayer *minuteLayer;

//时针的层
@property (weak,nonatomic) CALayer *hourLayer;

@end

@implementation ViewController
//每一秒转的度数
#define secondA 6

//每一分转的度数
#define minuteA 6

//每一小时要转的度数
#define hourA 30

//角度转弧度
#define angleRad(angle) ((angle)/180 * M_PI)

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //每一秒转6度,获取当前多少秒*6得到要转的角度
    
    
    
    //添加秒针
   self.secondLayer = [self addShiZhenWithHeight:80 width:1 color:[UIColor redColor]];
    
    //添加分针
    self.minuteLayer = [self addShiZhenWithHeight:70 width:3 color:[UIColor blackColor]];
    
    //添加时针
    self.hourLayer = [self addShiZhenWithHeight:50 width:4 color:[UIColor blackColor]];
    
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
    
    [self timeChange];
}

//添加时针
- (CALayer *)addShiZhenWithHeight:(CGFloat)height width : (CGFloat)width color:(UIColor *)color
{
    //实例化一个层
    CALayer *layer = [[CALayer alloc] init];
    
    //设置层的大小
    layer.frame = CGRectMake(self.clockView.frame.size.width * 0.5, self.clockView.frame.size.height * 0.5, width, height);
    
    //设置层的背景颜色
    layer.backgroundColor = color.CGColor;
    //设置层的位置
    layer.position = CGPointMake(self.clockView.frame.size.width * 0.5, self.clockView.frame.size.height * 0.5);
    layer.anchorPoint = CGPointMake(0.5, 1);
//    layer.transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
    //添加到父层
    [self.clockView.layer addSublayer:layer];
    return layer;
}

- (void)timeChange
{
    //获取系统日历
    NSCalendar * calendar = [NSCalendar currentCalendar];
    //components:日历单元:年,月,日,时,分,秒
    //fromDate:当前的日期
    //- (NSDateComponents *)components:(NSCalendarUnit)unitFlags fromDate:(NSDate *)date;
    
    NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond|NSCalendarUnitMinute|NSCalendarUnitHour fromDate:[NSDate date]];
    
    //获取当前是多少秒
    NSInteger curSecond = cmp.second;
    //秒针要转的度数
    CGFloat curSecondA = curSecond*secondA;
    self.secondLayer.transform = CATransform3DMakeRotation(angleRad(curSecondA), 0, 0, 1);
    
    //获取当前是多少分
    NSInteger curMinute = cmp.minute;
    //分针要转的度数
    CGFloat curMinuteA = curMinute * minuteA;
    self.minuteLayer.transform = CATransform3DMakeRotation(angleRad(curMinuteA), 0, 0, 1);
    
    //获取当前是几时
    NSInteger curHour = cmp.hour;
    //时针要转的度数+每改变一分时针要转0.5度
    CGFloat curHourA = curHour * hourA + curMinute * 0.5;
    self.hourLayer.transform = CATransform3DMakeRotation(angleRad(curHourA), 0, 0, 1);
     
}

你可能感兴趣的:([学习笔记]_核心动画)