CALayer

作者: 蔚尼 | 来源:发表于2018-06-26 16:13 被阅读16次

    本文主要记录CALayer的基本操作,UIView和CALayer的选择,CATransform3D。

    一.CALayer

    1.简介

    iOS中的事件传递和响应中记录过:遵循单一原则,UIView提供内容,处理触摸等事件,参与响应链;CALayer负责显示内容contents。

    当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并将内容绘制在自己的图层上,绘图完成后系统将图层拷贝到屏幕上进行UIView的显示;

    2.CALayer的疑惑

    为什么CALayer上面的颜色、图片是CGColorRefCGImageRef类型的?

    • 首先
      ->CALayer是定义在QuartzCore框架中的;
      ->CGColorRefCGImageRef两种数据类型是定义在CoreGraphics中的;
      ->UIImageUIColor是定义在UIKit框架中的;

    • 其次
      ->QuartzCore、CoreGraphics这两个框架可以跨平台在iOS和Mac OSX上都能使用;
      ->UIKit只能在iOS中使用

    • 所以,为了保证可移至性,QuartzCore不能使用UIImageUIColor

    3.CALayer使用

    其实我们一直都在用layer的这些属性,例如通过操作CALayer对象,可以很方便的调整UIView的一些外观属性:阴影、圆角、边框宽度和颜色、给图层添加动画效果...

    3.1 CALayer基本使用

    削圆的时候,非UIImageView设置cornerRadius即可;
    UIImageView的image是添加在imageView-->layer-->contents上面的;只是设置圆角无法看到效果,要把多余部分剪裁掉才可以,所以需要设置.layer.masksToBounds = YES;

        //设置边框(是添加到redView的里面:把边框改大可查看)
        self.redView.layer.borderColor = [UIColor blueColor].CGColor;
        self.redView.layer.borderWidth = 10;
        
        //设置阴影
        self.redView.layer.shadowOpacity = 1;
        self.redView.layer.shadowOffset = CGSizeMake(10, 10);
        self.redView.layer.shadowColor = [UIColor greenColor].CGColor;
    
        //设置圆角
        self.redView.layer.cornerRadius = 50;
        
        //UIImageView削圆
        //设置圆角
        self.imageView.layer.cornerRadius = 50;
        //超过根层以为的内容裁减掉(造成离屏渲染,CPU的工作交给了GPU,消耗性能)--->所以要使用Quartz 2D来剪裁
        self.imageView.layer.masksToBounds = YES;
    
    

    3.2 CALayer的属性--transform(CATransform3D)

    使用layer的transform属性可以进行旋转、平移、缩放;和UIView的transform相比:

    UIView的transform:CGAffineTransform类型
    layer的transform:CATransform3D类型(是3D空间的,比UIView的transform可做的多一些,比如对Z轴操作就需要layer的transform)

    3.2.1 平移、旋转、缩放

            //1.旋转
            //angle:旋转角度;X,Y,Z里面绕哪个轴旋转就为1;x,y都为1,就绕x,y中间的中轴旋转
            self.imageView.layer.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
            
            //2.平移
            //z:层级;值大的在上面
            self.imageView.layer.transform = CATransform3DMakeTranslation(50, 50, 1000);
            
            //不带make的,是相对于某一个来进行操作的;带make就是相对于原点操作的
            self.imageView.layer.transform = CATransform3DTranslate(self.imageView.layer.transform, 50, 50, 1000);
            
            //3.缩放
            self.imageView.layer.transform = CATransform3DScale( self.imageView.layer.transform, 1.5, 1.5, 1);
    

    3.2.2 通过KVC只对某一个值操作

    通过kvc使用场景,用来做快速变性操作,只做一个值的操作

         NSValue * value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
         [self.imageView.layer setValue:value forKey:@"transform"];
            
    

    eg:只让x放大

    [self.imageView.layer setValue:@(2) forKeyPath:@"transform.scale.x"];
    

    要设置的key参考如下表:


    kvc对应的key

    3.2.3.自定义CALayer

        CALayer * layer = [CALayer layer];
        layer.frame = CGRectMake(50, 50, 100, 100);
        layer.backgroundColor = [UIColor redColor].CGColor;
        layer.contents = (id)[UIImage imageNamed:@"1.png"].CGImage;
        [self.view.layer addSublayer:layer];
    

    也可以对自定义layer直接削圆、描边等操作。eg:

        //--添加头像外轮廓
        CALayer *avatarBorder = [CALayer layer];
        avatarBorder.frame = _avatarView.bounds;
        avatarBorder.borderWidth = CGFloatFromPixel(1);
        avatarBorder.borderColor = [UIColor colorWithWhite:0.000 alpha:0.090].CGColor;
        avatarBorder.cornerRadius = _avatarView.height / 2;
        avatarBorder.shouldRasterize = YES;
        avatarBorder.rasterizationScale = kScreenScale;
        [_avatarView.layer addSublayer:avatarBorder];
    

    4.CALayer和UIView的选择

    • CALayer做到的UIView也可以做,但是相比下来,CALayer的性能更高,更加轻量级。

    • 前面介绍CAlayer的基本操作,UIView也可以实现,那什么时候用CALayer、什么时候用UIView呢?
      ->不需要事件交互的使用CALayer;需要使用的使用UIView;
      ->但是为了可扩展性,一般需要使用UIView,以防目前不需要交互,后期需要交互;

    二. CALayer的属性:position、anchorposition

    CALayer的有两个很重要的属性:position、anchorposition;

    1.position

    • 用来设置CALyer在附赠中的位置
    • 父层的左上角为原点(0,0)

    2. anchorPosition(定位点、锚点)

    • anchorposition即layer的哪个点和position重合
    • 以自己的左上角为原点(0,0)
    • 它x、y取值范围是0-1,默认值为(0.5,0.5)

    如下图,假如红色图层以下几个点分别为锚点。
    第(1)个点为锚点时,(0,0)是锚点
    第(2)个点为锚点时,(0.5,0.5)是锚点
    第(3)个点为锚点时,(1,1)是锚点
    第(4)个点为锚点时,(0.5,1)是锚点

    示例图

    3.position和anchorPosition

    添加橘色图层到蓝色图层上面;
    橘色图层显示到什么位置,由position属性决定;

    (1)假设橘色图层的position是(100,100);橘色图层的anchorPosition是(0,0);即橘色图层的(0,0)点和蓝色图层的(100,100)重合

    示例

    (2)假设橘色图层的position是(100,100);橘色图层的anchorPosition是(0.5,0.5);即橘色图层的(0.5,0.5)点和蓝色图层的(100,100)重合

    示例

    (3)假设橘色图层的position是(100,100);橘色图层的anchorPosition是(1,1);即橘色图层的(1,1)点和蓝色图层的(100,100)重合

    示例

    4.代码示例

    自定义layer,anchorPosition默认为(0.5,0.5);
    设置layer的position为 self.view.center;
    相当于是让layer的center(0.5,0.5)和view的center重合;

    从而可以得到,当anchorPosition为(0.5,0.5)时,UIView的center就是内部layer的position。

        CALayer * layer = [CALayer layer];
        layer.backgroundColor = [UIColor redColor].CGColor;
    
        layer.bounds = CGRectMake(0, 0, 100, 100);
        layer.position = self.view.center;
        [self.view.layer addSublayer:layer];
    
    效果图

    5.隐式动画

    每个UIView关联的CALayer,称为Root Layer(根层);
    所有手动创建的layer,即非根层,都存在着隐式动画;

    什么是隐式动画?

    当对非根层layer的Animatable Properties(可动画属性)进行修改时,会默认产生一些动画。

    Animatable Properties:
    bunds:修改这个属性会产生缩放动画;
    backgroundColor:修改会产生背景色渐变动画;
    position:修改会产生平移动画

    取消隐式动画

    隐示动画封装了一个事务;我们可以使用CATransaction,把要取消的动画放到事务里面。

    如下:

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        //取消隐式动画
        [CATransaction setDisableActions:YES];
    
        self.layer.position = self.view.center;
        
        //捆绑哪些操作,如果不写的话,系统会自动给所有动画加上
        [CATransaction commit];
        
        self.layer.cornerRadius = 30;
    }
    
    

    6.显示动画

    既然有隐式动画,那肯定有显示动画。显示动画就是我们平时所指的Core Animation。比如属性动画、动画组、过渡等。详细可以看Core Animation

    三. CALayer的属性:contentGravity

    这个属性类似于的contentMode,目的是为了决定内容在图层的边界中怎么对齐。

    view.contentMode = UIViewContentModeScaleAspectFit;
    

    如下,把一个正方形的image添加到蓝色的长方形layer里面(左图是对齐前,右图是对齐后):

        //创建layer
        CALayer *blueLayer = [CALayer layer];
        blueLayer.frame = CGRectMake(50.0f, 50.0f, 200.0f, 300.0f);
        blueLayer.backgroundColor = [UIColor blueColor].CGColor;
    
        //添加image到contents    
        UIImage *image = [UIImage imageNamed:@"1"];
        blueLayer.contents =  (id)image.CGImage;
    
        //设置对齐方式
        blueLayer.contentsGravity = kCAGravityResizeAspect;    
        
        [self.view.layer addSublayer:blueLayer];
    
    
    效果图

    四. CALayer的属性:contentsScale

    如果我们把contentsGravity设置为kCAGravityCenter(这个值并不会拉伸图片),图片显示如下,很明显图片超过了layer很多,也虚化了。

         //创建layer
        CALayer *blueLayer = [CALayer layer];
        blueLayer.frame = CGRectMake(50.0f, 50.0f, 200.0f, 300.0f);
        blueLayer.backgroundColor = [UIColor blueColor].CGColor;
        
        //添加image到contents    
        UIImage *image = [UIImage imageNamed:@"1"];
        blueLayer.contents =  (id)image.CGImage;
    
        //设置显示为中间对齐    
        blueLayer.contentsGravity = kCAGravityCenter;
        
        [self.view.layer addSublayer:blueLayer];
    
    效果图
    • 这个时候需要contentsScale,contentsScale默认为1。
    • contentsScale属于支持高分辨率(又称Hi-DPI或Retina)屏幕机制的一部分。用来判断在绘制图层的时候应该为创建的空间大小。
    • 如果contentsScale设置为1.0,将会以每个点1个像素绘制图片,如果设置为2.0;则会以每个点2个像素绘制图片,这就是我们熟知的Retina屏幕。

    换句话说:
    contentScale:决定着绘制图层的时候,1个点对应几个像素。例如iphone6、7、8,1个点对应2个像素。那么contentScale应该就为2。iphone6p、7p,1个点对应3个像素,contentScale应该就为2。
    通过[UISCreen mainScreen].scale可获取当前屏幕每个点需要对应几个像素。

    刚刚没有设置contentScale,默认1个点对应1个像素,所以虚化了。现在修改后,效果如下:

        CALayer *blueLayer = [CALayer layer];
        blueLayer.frame = CGRectMake(50.0f, 50.0f, 200.0f, 300.0f);
        blueLayer.backgroundColor = [UIColor blueColor].CGColor;
        
        UIImage *image = [UIImage imageNamed:@"1"];
        blueLayer.contents =  (id)image.CGImage;
        
        blueLayer.contentsGravity = kCAGravityCenter;
        //设置contentScale
        blueLayer.contentsScale = [UIScreen mainScreen].scale;
    
        [self.view.layer addSublayer:blueLayer];
    
    效果图

    相关文章

      网友评论

          本文标题:CALayer

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