• iOS学习——核心动画之Layer基础


    iOS学习——核心动画之Layer基础 

    1、CALayer是什么?

    CALayer我们又称它叫做层在每个UIView内部都有一个layer这样一个属性UIView之所以能够显示就是因为它里面有这个layer才具有显示的功能我们可以通过操作CALayer对象可以很方便地调整UIView的一些外观属性可以给UIView设置阴影,圆角,边框等等... 

    2、如何操作layer改变UIView外观?

      2.1 设置阴影

    //默认图层是有阴影的, 只不过,是透明的
    _RedView.layer.shadowOpacity = 1;
    
    //设置阴影的圆角
    _RedView.layer.shadowRadius  =10;
    
    //设置阴影的颜色,把UIKit转换成CoreGraphics框架,用.CG开头
    _RedView.layer.shadowColor = [UIColor blueColor].CGColor;

        2.2.设置边框 

    //设置图层边框,在图层中使用CoreGraphics的CGColorRef
    _RedView.layer.borderColor = [UIColor whiteColor].CGColor;
     _RedView.layer.borderWidth = 2;

    2.3.设置圆角

    //图层的圆角半径,圆角半径为宽度的一半, 就是一个圆
    _RedView.layer.cornerRadius = 50;

    3、如何操作layer改变UIImageView的外观? 

    //设置图形边框
    _imageView.layer.borderWidth = 2;
    _imageView.layer.borderColor = [UIColor whiteColor].CGColor;
    
    //设置图片的圆角半径,必须要进行第二步的裁剪,超出裁剪区域的部分全部裁剪掉
    _imageView.layer.cornerRadius = 50;
    _imageView.layer.masksToBounds = YES; 

        注意设置图片的圆角时,除了设置圆角半径,还必须要进行第二步的裁剪,设置masksToBounds为yes这是因为UIImageView当中Image并不是直接添加在层上面的,这是添加在layer当中的contents里。UIImageView中是UIView的主layer上添加了一个次layer(用来绘制contents),我们设置边框的是主layer,但是次layer在上变,不会有任何的影响,所以当我们调用切割语句的时候,超出边框意外的都被切割了!!

        我们设置层的所有属性它只作用在层上面对contents里面的东西并不起作用所以如果我们不进行裁剪,我们看不到图片圆角效果的。想要让图片有圆角的效果,就必须把masksToBounds这个属性设为YES当设为YES把就会把超过根层以外的东西都给裁剪掉 

    4、layer的 CATransform3D属性变换      

      UIView和Layer都有transform属性,但是他们的所属有区别,类型也有区别

    1.picView.transform是二维的属性,是CGAffineTransform类型
    2.picView.layer.transform是layer级别的三维属性,是CATransform3D类型的,当然也可以做二维的事情,只有旋转的时候才可以看出3D的效果.

    //旋转  x,y,z 分别代表x,y,z轴.
    CATransform3DMakeRotation(M_PI, 1, 0, 0);
          
    //平移
    CATransform3DMakeTranslation(x,y,z)
          
    //缩放
    CATransform3DMakeScale(x,y,z);

      属性设置有三种方法

    //1.直接使用基本的三维赋值方法
    picView.layer.transform = CATransform3DMakeScale(1, 2.5, 0);
            
    //2.使用KVC将CATransform3DMakeScale生成的对象给layer
    NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
    [picView.layer setValue:value forKeyPath:@"transform.scale"];
            
    //3.使用快捷方法设置属性
    [picView.layer setValue:@5 forKeyPath: "transform.scale.y"];

          什么时候用KVC?

          当需要做一些快速缩放,平移,二维的旋转时用KVC。后面forKeyPath属性值不是乱写的,苹果文档当中给了相关的属性.

          比如: [_imageView.layer setValue:@0.5 forKeyPath:@"transform.scale"];

    5、如何自定义Layer ?

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

    //创建
    CALayer *layer = [CALayer layer];
    //设置尺寸和位置
    layer.frame = CGRectMake(50, 50, 100, 100);
    //设置背景
    layer.backgroundColor = [UIColor redColor].CGColor;
    //给layer设置图片.
    layer.contents = (id)[UIImage imageNamed:@"image001"].CGImage;
    //加载绘制
    [self.view.layer addSublayer:layer];

      6、为什么要使用CGImageRef、CGColorRef?

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

      7、UIView和CALayer都能够显示东西,该怎样选择?

      在明白要怎么选择之前,我们先了解一下UIView和layer的不同点:

      • 在iOS中看的见,摸得着的都是UIView,例如一个按钮,UITextField,UILable等等,都是UIView
      • UIView之所以能够显示在屏幕上,是试音UIView中有一个图层
      • 在创建UIView的时候,系统会自动创建一个CALayer在其中,用于显示东西,可以通过view.layer来去获取图层属性
      • 当UIView要去显示的时候,先去调用drawRect方法,将要绘制的东西绘制到图层上,然后拷贝图层,完成了UIView的显示
      • UIView只有交互的功能,没有显示的功能
      • CALayer只要显示的功能,没有交互的功能
      • UIView可以做一些简单的动画,例如:平移,拉伸,旋转
      • 一些比较高端的动画,都是直接操作CALayer的,可以制作3D动画
      • 使用CALayer,可以直接操作显示的东西,例如阴影,圆角,边框等

    所以,对比CALayer,UIView多了一个事件处理的功能。也就是说,CALayer不能处理用户的触摸事件,而UIView可以

    如果显示出来的东西需要跟用户进行交互的话,用UIView;

      如果不需要跟用户进行交互,用UIView或者CALayer都可以CALayer的性能会高一些,因为它少了事件处理的功能,更加轻量级

    8、position和anchorPoint?

      position和anchorPoint是CAlayer的两个属性我们以前修改一个控件的位置都是过Frame的方式进行修改现在CALayer则是通过position和anchorPoint属性也能够修改控件的位置

    这两个属性是配合使用的

      position:它是用来设置当前的layer在父控件当中的位置的默认它的坐标原点以父控件的左上角为(0.0)点

      anchorPoint就是把锚点定到position所指的位置。它是决点CALayer身上哪一个点会在position属性所指的位置anchorPoint它是以当前的layer左上角为原点(0.0)它的取值范围是0~1,它的默认在中间也就是(0.5,0.5)的位置

      两者结合使用想要修改某个控件的位置我们可以设置它的position点设置完毕后layer身上的anchorPoint会自动定到position所在的位置

    //下面两行代码就是设置views的 正中间 坐标(200,200)
    _views.layer.position = CGPointMake(200, 200);
    _views.layer.anchorPoint = CGPointMake(0.5, 0.5);
    
    //下面两行代码就是设置views的 左上角 坐标(200,200)
    _views.layer.position = CGPointMake(200, 200);
    _views.layer.anchorPoint = CGPointMake(0, 0);
    
    //下面两行代码就是设置views的 右下角 坐标(200,200)
    _views.layer.position = CGPointMake(200, 200);
    _views.layer.anchorPoint = CGPointMake(1, 1);

    9、隐式动画

    9.1 什么是隐式动画?

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

      • 根层UIView内部自动关联着的那个layer我们称它是根层.
      • 非根层自己手动创建的层称为非根层.

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

    9.2 如何取消隐式动画?

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

    什么是事务? 很多操作绑定在一起当这些操作执行完毕后才去执行下一个操作.

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

    10、时钟效果

    10.1 搭建界面

      界面上时针分针秒针不需要与用户进行交互所以都可以使用layer方式来做具体时间可以用用一张圆形图片来显示,然后在这个imageView的layer中进行时针、分针和秒针的绘制。

      做之前要观察时针在做什么效果是根据当前的时间绕着表盘的中心点进行旋转.

      要了解一个非常重要的知识点无论是旋转缩放它都是绕着锚点进行的。要想让时针分针称针显示的中间还要绕着中心点进行旋转那就要设置它的position和anchorPoint两个属性.

    //添加秒针
    - (void)addSecond{
        //创建秒针
        CALayer *layer = [CALayer layer];
        _secondL = layer;
        //设置宽高
        layer.bounds = CGRectMake(0, 0, 1, 80);
        //设置锚点为秒针的 x轴中心,y轴最右端,该锚点的位置是时钟图片的正中心
        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;
        //将秒针的layer添加到时钟图片的layer中
        [_clockView.layer addSublayer:layer];
        
    }
    
    //时针、分针的添加方式类似,只是设置的宽高有点区别,不再贴出来

    10.2 让秒针开始旋转.   

    //角度转换成弧度
    #define angle2Rad(angle) ((angle) / 180.0 * M_PI)
    
    //每一秒 秒针 旋转6度
    #define perSecondA 6
    //每一分 分针 旋转
    #define perMinA 6
    //每一小时 时针 旋转30
    #define perHourA 30
    //第一分钟 时针 旋转0.5
    #define perMinHour 0.5
    
    //每一秒调用一次
    - (void)timeChage{
        
        NSCalendar *calendar = [NSCalendar currentCalendar];
        //components日历单元:年,月,日,时,分,秒
        //fromDate:从哪个时间开始取
        NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour fromDate:[NSDate date]];
        //获取当前时间的时 分 秒
        NSInteger curSecond =  cmp.second;
        NSInteger curMinute =  cmp.minute;
        NSInteger curHour = cmp.hour;
    
        //秒针 旋转多少度. 当前的秒数乘以每秒转多少度.
        CGFloat angle = curSecond * perSecondA;
        self.secondL.transform = CATransform3DMakeRotation(angle2Rad(angle), 0, 0, 1);
        //分针 旋转多少度. 当前的分钟乘以每分转多少度.
        CGFloat minuteA = curMinute * perMinA;
        self.minuteL.transform =  CATransform3DMakeRotation(angle2Rad(minuteA), 0, 0, 1);
     
        //时针旋转的度数应该是 多少小时对应的度数+分钟对应的时针旋转的度数
        CGFloat hourA = curHour * perHourA + curMinute * perMinHour;
        self.hourL.transform =  CATransform3DMakeRotation(angle2Rad(hourA), 0, 0, 1);
    }

    10.3 将布局和旋转进行组合

    每过一秒,我们的秒针就需要变化位置,所以我们我们需要设置一个定时器,在开始时每秒执行一次旋转布局绘制。

    - (void)viewDidLoad {
        [super viewDidLoad];
        //添加时针 分针 秒针
        [self addHour];
    
        [self addMinue];
    
        [self addSecond];
        
        //添加定时器,每秒进行绘制
        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChage) userInfo:nil repeats:YES];
       
     //绘制
        [self timeChage];
        
    }

            

      

  • 相关阅读:
    一元运算符重载 前置和后置++ --(这种一般用成员函数来实现重载)
    运算符中的二元重载,为什么要调用友元函数而不是全局函数的问题
    关于数组的封装不知道为什么错了,具体代码如下
    关于对象的动态建立和释放
    关于构造函数中调用构造函数的危险
    关于析构函数,构造函数匿名对象的总结,以厚忘了,可以回来观看很全
    关于深拷贝和浅拷贝的疑问
    构造函数的调用大全
    构造函数的调用(其中不包括赋值构造函数)
    LeetCode:Add Digits
  • 原文地址:https://www.cnblogs.com/mukekeheart/p/9371508.html
Copyright © 2020-2023  润新知