CALayer

本文主要记录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参考如下表:


CALayer_第1张图片
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)是锚点

CALayer_第2张图片
示例图

3.position和anchorPosition

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

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

CALayer_第3张图片
示例

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

CALayer_第4张图片
示例

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

CALayer_第5张图片
示例

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];
CALayer_第6张图片
效果图

5.隐式动画

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

什么是隐式动画?

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

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

取消隐式动画

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

如下:

-(void)touchesBegan:(NSSet *)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_第7张图片
效果图

四. 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];
CALayer_第8张图片
效果图
  • 这个时候需要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_第9张图片
效果图

你可能感兴趣的:(CALayer)