IOS--CALayer(图层类)

##1、CALayer概述

CALayer类在概念上和UIView类似,同样也是一些被层级关系 树管理的矩形块,同样也可以包含一些内容(像图片,文本或者背景色),管理子图层的位置。它们有一些⽅法和属性用来做动画和变换。 CALayer是CoreAnimation部分的内容,CALayer的概念类似于photoshop中层的概念,每个UIView都有一个根CALayer,每个CALayer又可以添加子CALayer,从结构上来看CALayer是一种树形结构,UIView的绘制工作都交由CALayer完成。

和UIView最大的不同是CALayer不处理⽤用户的交互。因为CALayer并不清楚具体的响应链(iOS通过视图层级关系用来传送触摸事件的机制),于是它并不能够响应事件,即使它提供了一些方法来判断是否一个触点在图层的范围之内。

##2、平行的层级关系 每一个UIview都有一个CALayer实例的图层属性,也就是所谓的backing layer,视图的职责就是创建并管理这个图层,以确保当子视图在层级关系中添加或者被移除的时候,他们关联的图层也同样对应在层级关系树当中有相同的操作。 实际上,这些背后关联的图层才是真正用来在屏幕上显示和做画,UIView仅仅是对CALayer的一个封装,然后提供了处理触摸的具体功能,以及CoreAnimation高级接口。但是为什么iOS要基于UIView和CALayer提供两个平行的层级关系呢?为什么不⽤一个简单的层级来处理所有事情呢?原因在于要做职责分离,这样也能避免很多重复代码。在iOS和Mac OS两个平台上,事件和⽤户交互有很多地方的不同,基于多点触控的用户界⾯和基于⿏标键盘有着本质的区别,这就是为什么iOS有UIKit和UIView,但是Mac OS有AppKit和NSView的原因。他们功能上很相似,但是在实现上有着显著的区别。

实际上,这里并不是两个层级关系,而是四个,每一个都扮演不同的角色,除了视图层级和图层树之外,还存在呈现树和渲染树.

  • 呈现树:呈现树包含了当前动画发生时候将要显示的值,例如你要给图层背景颜色设置新的值的时候,它会立即修改图层树里面相应的值。但是在呈现树里面背景颜色值在将要显示给用户的时候才被更新为新值。

  • 渲染树:渲染树是私有的,你无法访问到,渲染树在渲染图层的时候使用呈现树的值,为了不阻塞主线程,渲染的过程是在单独的进程或线程中进行的,所以你会发现Animation的动画并不会阻塞主线程。

前⾯面已经讲过,UIView是对CALayer的封装,那为什么我们还要学习CALayer呢?因为UIView封装的 API在有些情况下并不能满足我们的需求,比如:


1.阴影,圆⾓角,边框       
2.3D变换    
3.⾮矩形范围    
4.遮罩    
5.⾮线性动画   

##3、CALayer常用属性 我们可以进入CALayer.h中查看CALayer支持的属性,其中注解中标注Animation的属性表示支持隐式动画,当这些属性的值改变时系统自带了平滑过渡的动画效果(非根Layer支持)

下表列出了CALayer常用的属性:

属性说明是否支持隐式动画
anchorPoint和中心点position重合的一个点,称为“锚点”,锚点的描述是相对于x、y位置比例而言的默认在图像中心点(0.5,0.5)的位置
backgroundColor图层背景颜色
borderColor边框颜色
borderWidth边框宽度
bounds图层大小
contents图层显示内容,例如可以将图片作为图层内容显示
contentsRect图层显示内容,例如可以将图片作为图层内容显示
contentsRect图层显示内容的大小和位置
cornerRadius圆角半径
doubleSided图层背面是否显示,默认为YES
frame图层大小和位置,不支持隐式动画,所以CALayer中很少使用frame,通常使用bounds和position代替
zPosition图层的重叠顺序
hidden是否隐藏
mask图层蒙版
maskToBounds是否剪切超出父图层边界的部分,默认为NO
opacity透明度 ,类似于UIView的alpha
position图层中心点位置,类似于UIView的center
shadowColor阴影颜色
shadowOffset阴影偏移量
shadowOpacity阴影透明度,注意默认为0,如果设置阴影必须设置此属性
shadowPath阴影的形状
shadowRadius阴影模糊半径
sublayers设置多个子图层
sublayerTransform子图层形变
transform图层形变
  • 隐式属性动画的本质是这些属性的变动默认隐含了CABasicAnimation动画实现,详情大家可以参照Xcode帮助文档中“Animatable Properties”一节。
  • 在CALayer中很少使用frame属性,因为frame本身不支持动画效果,通常使用bounds和position代替。
  • CALayer中透明度使用opacity表示而不是alpha;中心点使用position表示而不是center。
  • anchorPoint属性是图层的锚点,范围在(0~1,0~1)表示在x、y轴的比例,这个点永远可以同position(中心点)重合,当图层中心点固定后,调整anchorPoint即可达到调整图层显示位置的作用(因为它永远和position重合)

创建layer并添加到根layer上:

    CALayer *layer = [[CALayer alloc] init];
    layer.frame = CGRectMake(10, 320, 330, 200);
    layer.backgroundColor = [UIColor blueColor].CGColor;
    
    // 将图层添加到父图层
    [self.view.layer addSublayer:layer];   

填充图片内容,需要将 UIImage 桥接(__bridge)到CGImage:

    layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"image4.jpg"].CGImage);
    

使用layer CATextLayer 子类填充文字:

    CATextLayer *textLayer = [[CATextLayer alloc] init];
    textLayer.frame = CGRectMake(10, 550, 300, 30);
    textLayer.string = @"这是layer填充的文字内容";
    //字体颜色
    textLayer.foregroundColor = [UIColor blackColor].CGColor;
    textLayer.backgroundColor = [UIColor redColor].CGColor;
    textLayer.font = (__bridge CFTypeRef _Nullable)([UIFont systemFontOfSize:20 weight:500]);
    textLayer.fontSize = 20;
    textLayer.alignmentMode = @"center";
    // textLayer.truncationMode = @"middle";
    
    [self.view.layer addSublayer:textLayer];

##4、CALayer图层绘制

  • 通过直接设置CALayer的contents属性进行图层绘制
   CALayer *layer = [CALayer layer];
    // layer.frame = CGRectMake(0, 100, 350, 200);
    layer.backgroundColor = [UIColor orangeColor].CGColor;
    
    // 1、bounds: 尺寸
    layer.bounds = CGRectMake(0, 0, 220, 220);
    // 2、position: 定位点
    layer.position = self.view.center;
    
    // 3、锚点、支点:决定layer上的哪个点在 position 点上,默认(0.5, 0.5),范围:(0,0) ~ (1,1)
    layer.anchorPoint = CGPointMake(0.5, 0.5);
    
    // 4、z方向的层级
    layer.zPosition = 2;
    
    // 5、设置圆角:为直径的一半时会成圆形
    layer.cornerRadius = 110;
    
    // 6、填充内容
    layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"image1.jpg"].CGImage);
    //设置背景颜色
    layer.backgroundColor = [UIColor orangeColor].CGColor;
    // 7、是否可以裁剪多余的图层
    layer.masksToBounds = YES;
    
    // 8、设置边框宽度和颜色
    //layer.borderWidth = 5;
    //layer.borderColor = [UIColor lightGrayColor].CGColor;
    
    [self.view.layer addSublayer:layer];
    
}

实现效果:

需要注意的是上面代码中绘制图片圆形裁切效果时如果不设置masksToBounds是无法显示圆形,但是对于其他图形却没有这个限制。原因就是当绘制一张图片到图层上的时候会重新创建一个图层添加到当前图层,这样一来如果设置了圆角之后虽然底图层有圆角效果,但是子图层还是矩形,只有设置了masksToBounds为YES让子图层按底图层剪切才能显示圆角效果。

  • 扩展--带阴影效果的圆形图片裁切

如果设置了masksToBounds=YES之后确实可以显示图片圆角效果,但遗憾的是设置了这个属性之后就无法设置阴影效果。因为masksToBounds=YES就意味着外边框不能显示,而阴影恰恰作为外边框绘制的,这样两个设置就产生了矛盾。要解决这个问题不妨换个思路:使用两个大小一样的图层,下面的图层负责绘制阴影,上面的图层用来显示图片。

    //阴影图层
    CALayer *layerShadow = [[CALayer alloc]init];
    layerShadow.bounds = CGRectMake(0, 0, 220, 220);
    layerShadow.position= self.view.center;
    layerShadow.cornerRadius = 110;
    //阴影颜色
    layerShadow.shadowColor = [UIColor grayColor].CGColor;
    //阴影偏移量
    layerShadow.shadowOffset = CGSizeMake(5, 1);
    //阴影透明度
    layerShadow.shadowOpacity = 1;
    layerShadow.borderColor = [UIColor whiteColor].CGColor;
    layerShadow.borderWidth = 5;
    
    [self.view.layer addSublayer:layerShadow];
}

实现效果:

##5、CALayer3D变换

  • 隐式动画: 当layer的属性发生变换时会默认产生动画效果,动画时间0.25s
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    UITouch *touch=[touches anyObject];
    CGFloat width=layer.bounds.size.width;
    
    if (width==Width) {
        width=Width*2;
        // 组合 CATransform3D
        CATransform3D transform_01 = CATransform3DScale(layer.transform, 1, 1, 1);
        CATransform3D transform_02 = CATransform3DRotate(layer.transform, M_PI/6, 0, 0, 1);
        layer.transform = CATransform3DConcat(transform_01, transform_02);
        layer.cornerRadius = width/2;
        layer.backgroundColor = [UIColor blueColor].CGColor;
    }else{
        width=Width;
        layer.cornerRadius = 0;
        layer.backgroundColor = [UIColor orangeColor].CGColor;
    }
    layer.bounds=CGRectMake(0, 0, width, width);
    layer.position=[touch locationInView:self.view];
    
}
@end

实现效果:

  • CATransform3D数据结构定义了一个三维变换(4x4 CGFloat值的矩阵),用于图层的旋转,缩放,偏移,歪斜和应用的透视,常用函数有下面几种:

1:CATransform3DMakeRotation(CGFloat angle, <#CGFloat x#>, <#CGFloat y#>, <#CGFloat z#>)

如果x=1,y=0,z=0则绕x轴旋转angle角度

如果x=0,y=1,z=0则绕y轴旋转angle角度

如果x=0,y=0,z=1则绕z轴旋转angle角度

如果x=1,y=1,z=0则绕x轴和y轴夹角旋转angle角度

如果x=1,y=1,z=1则绕3轴夹角旋转angle角度

上诉的旋转中心都是layer的锚点(anchorPoint)

2:CATransform3DRotate(<#CATransform3D t#>, <#CGFloat angle#>, <#CGFloat x#>, <#CGFloat y#>, <#CGFloat z#>)  功能与上一函数类似,但可以叠加一个CATransform3D效果

3:CATransform3DMakeScale(<#CGFloat sx#>, <#CGFloat sy#>, <#CGFloat sz#>) 用于缩放,三个参数是x轴,Y轴,z轴上的缩放程度,缩放中心是layer的锚点

4:CATransform3DScale(<#CATransform3D t#>, <#CGFloat sx#>, <#CGFloat sy#>, <#CGFloat sz#>)   功能与上一函数类似,但可以叠加一个CATransform3D效果

5:CATransform3DMakeTranslation(CGFloat tx, <#CGFloat ty#>, <#CGFloat tz#>)  用于平移

6:CATransform3DTranslate(<#CATransform3D t#>, <#CGFloat tx#>, <#CGFloat ty#>, <#CGFloat tz#>) 用于移动

7:CATransform3DConcat(CATransform3D a, <#CATransform3D b#>) 将两个CATransform3D效果叠加起来

我们也可以通过KVC更方便的设置transform的属性

[layer setValue:@M_PI forKeyPath:@"transform.rotation.x"];

可以通过KVC设置以下与transform相关的属性

transform.rotation.x

``transform.rotation.y`

transform.rotation.z

transform.scale.x

transform.scale.y

transform.scale.z

transform.translation.x

transform.translation.y

transform.translation.z

##6、CALayer事务 CALayer中"Animatable"属性变化都在CATrasaction的管理内,之前提到的属性支持隐式动画是指在某次Runroop中修改"Animatable"时,如果没有设置事务,则会自动创建一个CATransaction,并在当前线程的下一个RunLoop中commit这个CATransaction。

事务可以被嵌套,允许你禁用部分动画的行为或者在属性被修改的时候产生 的动画使用不同的时间。仅当最外层的事务被提交的时候,动画才会发生。

事务开启:[CATransaction begin]
禁止动画效果:[CATransaction setDisableActions:YES];
事务提交:[CATransaction commit]

我们可以通过事务控制动画的时长,甚至禁止动画效果,还可以设置completionBlock,当当前CATransaction的所有动画执行结束后,,completionBlock会被调用

##Demo下载地址: https://github.com/fuxinto/HfxDemo

转载于:https://my.oschina.net/6603044/blog/737810

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值