简介
在iOS系统中,看得见摸得着的基本都是UIView,如一个按钮、一个文本标签等,这些都是UIView。它能显示在屏幕上,是因为它内部的一个层,即CALayer对象。CALayer是被定义在QuartzCore框架中的,并不包含在UIKit中,它不能响应事件。
- CALayer和UIView的关系
在UIView中有一个layer属性作为根图层,根图层上可以放其他子图层,在UIView中所有能够看到的内容都包含在layer中。
在创建UIView对象时,它内部会自动创建一个CALayer对象,通过view.layer
可以访问。当UIView需要显示到屏幕上时,会调用drawRect:
进行绘图,并将所有内容绘制在自己的层上。绘图完毕后,系统会将层拷贝到屏幕上,于是就完成了UIView的显示。
基本使用
通过操作这个CALayer对象,可以设置UIView的一些界面属性,如:阴影、圆角大小、边框宽度和颜色等。
- 设置view旋转一定角度
利用transform
属性可以设置旋转、缩放等效果。
imgv.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
M_PI_4
表示四分之π
,顺时针旋转45°
后面的(0, 0, 1)
表示Z轴这个向量,修改这个向量可以做一些三维旋转效果。总体的意思是layer会绕着Z轴顺时针旋转45°,即在x、y平面进行旋转。
常用属性
-
中心点
position
图层中心点的位置,CGPoint类型,用来设置CALayer在父层中的位置;以父层的左上角为原点(0,0) -
锚点
anchorPoint
决定着CALayer身上的哪个点会再position属性所指的位置。以自己的左上角为原点(0,0) 范围在(01,01)表示在x、y轴的比例,默认在图像中心点(0.5,0.5)的位置;
-
- contents
图层显示内容,例如可以将图片作为图层内容显示。一定要转换为CGImage。
UIImage *img = [UIImage imageNamed:@"xxx"];
layer.contents = (id)img.CGImage;
-
contentsRect
图层显示内容的大小和位置。 -
doubleSided
图层背景是否显示,默认是YES -
transform
可以设置旋转、缩放等效果。 -
opacity
透明度 -
backgroundColor
borderColor
borderWidth
cornerRadius
hidden
shadowColor
shadowOffset 阴影偏移量
shadowOpacity
阴影透明度,注意默认为0,如果设置阴影必须设置此属性
shadowPath
阴影形状,CGPathRef类型
shadowRadius
-
mask
图层蒙版 -
masksToBounds
子图层是否剪切图层边界,默认是NO -
bounds
-
frame
图层大小和位置,不支持隐式动画,所以CALyaer中很少使用frame,通常使用bound和position代替
阴影效果无法和
masksToBounds
同时使用,因为masksToBounds
是剪切外边框,而阴影效果刚好在外边框。
- 可以使用KVC设置属性
如:[layer setValue:@M_PI forKeyPath:@"transform.rotation.x"];
图层操作
// 添加子图层
- (void)addSublayer:(CALayer *)layer;
//将自己从父图层中移除
- (void)removeFromSuperlayer;
//在自己子图层数组中的第idx位置添加图层
- (void)insertSublayer:(CALayer *)layer atIndex:(unsigned)idx;
//将图层layer添加在子图层sibling的下面
- (void)insertSublayer:(CALayer )layer below:(nullable CALayer )sibling;
//将图层layer添加在子图层sibling的上面
- (void)insertSublayer:(CALayer )layer above:(nullable CALayer )sibling;
//将图层layer替换layer2;
- (void)replaceSublayer:(CALayer )layer with:(CALayer )layer2;
动画操作
//图层添加某一属性的动画
- (void)addAnimation:(CAAnimation )anim forKey:(nullable NSString )key;
//获取所有动画的属性
- (nullable NSArray< NSString > )animationKeys;
//获取某一属性的动画
- (nullable CAAnimation )animationForKey:(NSString )key;
//移除某一属性动画
- (void)removeAnimationForKey:(NSString *)key;
//移除所有动画
- (void)removeAllAnimations;
隐式动画
在iOS中CALayer的设计主要是为了内容展示和动画操作。CALayer的很多属性在修改时,都能形成动画效果。这种属性称为隐式动画属性。
但不是每个属性都支持隐式动画。看看属性声明,有
Animatable
注释的才支持。
隐式属性动画的本质是,这些属性的变动默认隐含了CABasicAnimation
动画实现
但是对于UIView的根视图层而言,属性的修改并不形成动画效果,因为很多情况下根图层更多的充当容器的作用。另外,UIView的根图层创建工作完全有iOS负责完成,无法重新创建。
- 简单例子
直接改变layer对象的位置属性position
会有一个平移动画后,到新的位置
CALayer *la = [[CALayer alloc] init];
la.backgroundColor = [UIColor redColor].CGColor;
la.cornerRadius = 10;
la.position = CGPointMake(100, 100);
la.bounds = CGRectMake(0, 0, 100, 100);
[self.view.layer addSublayer:la];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
la.position = CGPointMake(230, 230); // 改变属性 position
});
CALayer绘图
使用Quartz 2D绘图,是直接调用UIView的drawRect:
方法绘制图形、图像,这种方式的本质还是再图层中绘制。drawRect:
方法是由UIKit组件进行调用,因此厘米那可以使用到一些UIKit封装的方法进行绘制。而直接绘制到图层的方法并非UIKit直接调用,因此只能用原生的Core Graphics方法绘制。
- 图层绘制有两种方法,不管使用那种方法,绘制完,必须让图层调用
setNeedDisplay
方法,注意!
1、通过图层代理drawLayer:inContext:方法绘制
通过代理方法进行图层绘制,只要指定图层的代理,然后在代理对象中重写- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
即可。
例子:把图片绘制在一个layer上
// 遵守协议 <CALayerDelegate>
- (void)viewDidLoad {
// PHOTO_HEIGHT 为长度
CALayer *layer = [[CALayer alloc] init];
layer.bounds = CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT);
layer.position = CGPointMake(160, 200);
layer.cornerRadius = PHOTO_HEIGHT/2;
layer.masksToBounds = YES;
layer.delegate = self;
[self.view.layer addSublayer:layer];
// 调用setNeedsDisplay。否则代理方法不会被调用
[layer setNeedsDisplay];
}
#pragma mark 代理方法 - 绘制图形、图像到图层,参数中的ctx是图层的图形上下文
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
//这个图层就是上面定义的图层layer
CGContextSaveGState(ctx);
//图形上下文形变,解决图片倒立的问题
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -PHOTO_HEIGHT);
//注意这个位置是相对于图层而言的,不是屏幕.
CGRect ff = CGRectMake(0, 0, PHOTO_HEIGHT, PHOTO_HEIGHT);
//把图片绘制到layer上
UIImage *image = [UIImage imageNamed:@"xxx"];
CGContextDrawImage(ctx, ff, image.CGImage);
CGContextRestoreGState(ctx);
}
2、使用自定义图层绘图
只要编写一个类继承自CALayer,然后重写- (void)drawInContext:(CGContextRef)ctx;
方法,在其中绘图即可。
例如,绘制星星
创建一个CALayer的子类KCALayer。
-(void)drawInContext:(CGContextRef)ctx{
// 绘制一个正方形
// CGContextFillRect(ctx, CGRectMake(0, 0, 100, 100));
// 绘制一个椭圆形
// CGContextFillEllipseInRect(ctx, CGRectMake(50, 50, 150, 100));
// 自定义绘制一个星星
CGContextMoveToPoint(ctx, 94.5, 33.5);
CGContextAddLineToPoint(ctx,104.02, 47.39);
CGContextAddLineToPoint(ctx,120.18, 52.16);
CGContextAddLineToPoint(ctx,109.91, 65.51);
CGContextAddLineToPoint(ctx,110.37, 82.34);
CGContextAddLineToPoint(ctx,94.5, 76.7);
CGContextAddLineToPoint(ctx,78.63, 82.34);
CGContextAddLineToPoint(ctx,79.09, 65.51);
CGContextAddLineToPoint(ctx,68.82, 52.16);
CGContextAddLineToPoint(ctx,84.98, 47.39);
CGContextClosePath(ctx);
// 图形填充颜色
CGContextSetRGBFillColor(ctx, 0/255.0, 232.0/255.0, 84.0/255.0, 1);
CGContextSetRGBStrokeColor(ctx, 0/255.0, 232.0/255.0, 84.0/255.0, 1);
CGContextDrawPath(ctx, kCGPathFillStroke);
}
外界使用
- (void)viewDidLoad {
KCALayer *layer = [[KCALayer alloc] init];
layer.backgroundColor = [UIColor yellowColor].CGColor;
layer.bounds = CGRectMake(0, 0, 185, 185);
layer.position = CGPointMake(160,284);
//显示图层
[layer setNeedsDisplay];
[self.view.layer addSublayer:layer];
}
-
网友评论