前言
iOS中能看见的东西都是view 比如一个按钮 一个文本标签等。UIView之所以能显示在屏幕上 完全是因为内部的图层。
在创建UIView对象时 UIView内部会自动创建一个图层 CALayer对象 通过UIView的layer属性可以访问这个层
当UIView需要显示到屏幕上 会调用drawRect方法绘图 并且将所有内容绘制到自己图层上 绘图完毕 系统会将图层拷贝到屏幕上。于是就完成了UIView的显示。换句话 UIView本身不具有显示的功能。
CALayer简单使用
iOS6之前需要导入QuartzCore.framework。之后不需要 Xcode自动导入了。
1.属性设置
-(void)addView
{
CGRect rect = CGRectMake(10, 50, 100, 100);
UIView * view = [[UIView alloc]initWithFrame:rect];
[self.view addSubview:view];
//设置
view.layer.borderColor = [UIColor redColor].CGColor; //边框颜色
view.layer.borderWidth = 14;//边框宽度
view.layer.cornerRadius = 10;//圆角设置
view.layer.shadowColor = [UIColor blueColor].CGColor;//阴影颜色
}
-(void)addImageView
{
CGRect rect = CGRectMake(10, 200, 100, 100);
UIImageView * imgView = [[UIImageView alloc]initWithFrame:rect];
[self.view addSubview:imgView];
imgView.image = [UIImage imageNamed:@"123.jpg"];
//边框颜色
imgView.layer.borderColor = [UIColor redColor].CGColor;
//边框宽度
imgView.layer.borderWidth = 14;
//圆角大小
imgView.layer.cornerRadius = 10;
//阴影颜色
imgView.layer.shadowColor = [UIColor blueColor].CGColor;
//图片无圆角 是因为图片所在的layer非主层。设置超出范围剪切掉。
imgView.layer.masksToBounds = YES;
//旋转
imgView.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
// NSValue * value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_4, 0, 0, 1)];
// [imgView.layer setValue:value forKey:@"transform"];
// [imgView.layer setValue:@(M_PI_4) forKey:@"transform.rotation"];
//缩放
// imgView.layer.transform = CATransform3DMakeScale(0.5, 2, 0);
// [imgView.layer setValue:@(0.5) forKey:@"transform.scale.x"];
//平移
// imgView.layer.transform = CATransform3DMakeTranslation(100, 20, 10);
NSValue * translationSize = [NSValue valueWithCGSize:CGSizeMake(-100, -100)];
[imgView.layer setValue:translationSize forKey:@"translation"];
//该方法后面的key可以设置为各种的值:
/*
rotation rotation.x rotation.y rotation.z
scale scale.x scale.y scale.z
transform transform.x transform.y transform.z
translation
*/
}
新建CALayer
CALayer * layer = [CALayer layer];
[self.view.layer addSublayer:layer];
layer.backgroundColor = [UIColor redColor].CGColor;
layer.bounds = CGRectMake(0, 0, 100, 100);
layer.position = CGPointMake(200, 100);
UIImage * image = [UIImage imageNamed:@"123.jpg"];
layer.contents = (id)image.CGImage;
对比CALayer UIView多了一个事件处理功能 也就是说 CALayer不能处理用户的触摸事件 而UIView可以。
因此 如果需要事件交互 用UIView 否则用CALayer。CALayer性能更高一点。
有关CALayer
CALayer是定义在QuartzCore框架中的。
CGImageRef CGColorRef两种数据类型是定义在CoreGraphics框架中的
UIColor UIImage是定义在UIKit框架中的。
QuartzCore框架和CoreGraphics框架是可以跨平台使用 在iOS和Mac OSX上都能使用
但是UIKit只能在iOS中使用。
CALayer的两个重要的属性 position和anchorPoint
@property CGPoint position
//设置CALayer在父层的位置 以父层的左上角为原点(0,0)
@property CGPoint anchorPoint;锚点
//决定这CALayer的哪个点会在position所指的位置。
//以自己的左上角为原点(0,0) x y 取值范围都是0-1 默认值为(0.5,0.5)
CALayer的隐式动画
每一个UIView内部都默认关联一个CALayer 我们可以称这个Layer为Root Layer(根层)
所有的非Root Layer也就是手动创建的CALayer对象 都存在隐式动画。
当对非RootLayer得部分属性进行修改时 默认会自动产生一些动画效果
而这些属性称为Animatable Properties(可动画属性)
常见的可动画属性:
bounds:用于设置CALayer的宽度和高度 修改这个属性会产生缩放动画
backgroundColor:用于设置CALayer的背景色 修改这个属性会产生背景色渐变动画
CALayer * layer = [[CALayer alloc]init];
layer.bounds = CGRectMake(0, 0, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
layer.position = CGPointMake(100, 100);
// layer.anchorPoint = CGPointMake(10, 10);
[self.view.layer addSublayer:layer];
layer.opacity = 0.5;
_layer = layer;
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[CATransaction begin];
self.layer.opacity = 1;
[CATransaction setDisableActions:YES];
self.layer.backgroundColor = [UIColor blueColor].CGColor;
self.layer.position = CGPointMake(0,0);
[CATransaction commit];
}
自定义CALayer
1.创建类继承自CALayer 然后重写drawInContext方法
-(void)drawInContext:(CGContextRef)ctx
{
CGContextSetRGBFillColor(ctx, 1,0,0,1);
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 50, 50));
CGContextFillPath(ctx);
}
在控制器实现方法:
-(void)test1
{
//当前没有出现圆形 给定颜色 发现layer出现而圆形没有。
//显式调用setNeedsDisplay 出现
//只有明显滴调用setNeedsDisplay 才能调用drawIncontext方法。
MyLayer * layer =[[ MyLayer alloc]init];
layer.frame = CGRectMake(0, 0, 100, 100);
[layer setNeedsDisplay];
layer.backgroundColor = [UIColor blueColor].CGColor;
[self.view.layer addSublayer:layer];
}
第二种方法:指定view的代理为当前控制器,重写方法drawLayer:InContext
-(void)test2
{
//代理帮我画
CALayer * layer = [[CALayer alloc]init];
layer.frame = CGRectMake(0, 0, 100, 100);
layer.backgroundColor = [UIColor blueColor].CGColor;
layer.position = CGPointMake(100, 100);
layer.anchorPoint = CGPointZero;
[self.view.layer addSublayer:layer];
//指定代理方法
layer.delegate = self;
//当前指定代理 不需要遵守协议 那么 该代理是所有的对象都可以当我的代理
//测试后发现当前的layer上并没有圆形 debug后发现代理方法并没有执行。
//答案:想要画东西 必须显式调用setNeedsDisplay方法
[layer setNeedsDisplay];
}
#pragma mark - layer的代理方法
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
NSLog(@"%@",@"是否");
CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);
CGRect rect = CGRectMake(0, 0, 30, 30);
CGContextAddEllipseInRect(ctx, rect);
CGContextFillPath(ctx);
}
UIView完整的显示过程:
当UIview需要显示时,
1.内部的layer会准备好一个CGContext上下文
2.然后调用delegate的方法drawLayer:InContext方法。如果当前view设置代理为当前的控制器 必须重写drawLayer方法,
3.在调用drawLayer:InContext方法之后,会调用view自己的drawInRect方法。传入的Context绘图完毕,被拷贝到屏幕。