一、UIView和CALayer的其他关系
* UIView可以通过subviews属性访问所有的子视图,类似地,CALayer也可以通过sublayers属性访问所有的子层
* UIView可以通过superview属性访问父视图,类似地,CALayer也可以通过superlayer属性访问父层
如果两个UIView是父子关系,那么它们内部的CALayer也是父子关系。
二、自定义图层方法一
1、方法描述:创建一个CALayer的子类,然后覆盖drawInContext:方法,使用Quartz2D API进行绘图
2.在.m文件中覆盖drawInContext:方法,在里面绘图
只有明显地调用setNeedsDisplay方法,才会调用drawInContext:方法进行绘制
-(void)drawInContext:(CGContextRef)ctx//上下文 { //颜色,在这边使用UIColor是没有用的,CALayer是QuartzCore框架的,所有UI的东西是没有用的在这边 CGContextSetRGBFillColor(ctx, 1.0, 0, 1.0, 1); //画圆 CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 50, 50)); //渲染,直接实心绘制 CGContextFillPath(ctx); }
3、viewDidLoad方法中调用
CustomLayer *layer = [CustomLayer layer]; layer.bounds = CGRectMake(0, 0, 100, 100); layer.backgroundColor = [UIColor blueColor].CGColor; layer.anchorPoint = CGPointZero; //图层和view不一样,layer不会自动的调用drawInContext:,只有明显地调用setNeedsDisplay方法,才会调用drawInContext:方法进行绘制 [layer setNeedsDisplay]; [self.view.layer addSublayer:layer];
三、自定义view来绘制,与上面的自定义layer进行对比
//UIView绘制图形的drawRect: -(void)drawRect:(CGRect)rect { //需要主动拿图层上下文,然后在上下文中绘制图片 CGContextRef ctx = UIGraphicsGetCurrentContext(); //填充色 CGContextSetRGBFillColor(ctx, 1.0, 0, 1.0, 1); //画圆 CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 50, 50)); //渲染,直接实心绘制 CGContextFillPath(ctx); //上面所绘制的东西相当于下面这个语句,图形上下文中绘制的所有的东西传到图层中去了 //UIView能够显示,主要是layer,这里拿到的上下文就是图层方法-(void)drawInContext:(CGContextRef)ctx中传人的上下文 // [self.layer drawInContext:ctx]; }
四、自定义图层方法二,不需要自定义,不需要继承,通过代理进行绘制
- (void)viewDidLoad { [super viewDidLoad]; [self diyLayer2]; } #pragma make - 创建图层方法二 - (void)diyLayer2 { CALayer *layer = [CALayer layer]; layer.bounds = CGRectMake(0, 0, 100, 100); layer.backgroundColor = [UIColor blueColor].CGColor; layer.anchorPoint = CGPointZero; layer.position = CGPointMake(100, 100); //如果代理方法没有协议,说明任何对象都可以当它的代理,代表这个方法是NSObject对象的。进去看一下,是NSObject分类方法。 //一个view内部自带的图层的代理,默认就是view本身,不可以修改自带layer的代理 layer.delegate = self; //图层需要主动的调用绘制方法 [layer setNeedsDisplay]; [self.view.layer addSublayer:layer]; } #pragma make - 图层的代理方法 -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx { CGContextSetRGBFillColor(ctx, 1, 0, 0, 1); CGContextAddRect(ctx, CGRectMake(0, 0, 20, 20)); CGContextFillPath(ctx); }
五、通过代理方法自定义图层layer需要注意:
view根层的layer的代理就是view本身,view内部那个图层怎么会东西由view决定,view实现drawRect:
* 这里要注意的是:不能再将某个UIView设置为CALayer的delegate,因为UIView对象已经是它内部根层的delegate,再次设置为其他层的delegate就会出问题。UIView和它内部CALayer的默认关系图:
总之一句话:一个view内部自带的图层不可以改它的代理
//view根层的layer的代理就是view本身 //例子一 self.view.layer.delegate == self.view //例子二 UIView *view1 = [[UIView alloc]init]; view1.layer.delegate == view1; //例子三 UIImageView *imageview1 = [[UIImageView alloc]init]; imageview1.layer.delegate == imageview1 //不可以将控制器作为根层layer的代理,否则什么都出不来 imageview1.layer.delegate = self;
六:总结
无论采取哪种方法来自定义层,都必须调用CALayer的setNeedsDisplay方法才能正常绘图。
七:UIView的详细显示过程
* 当UIView需要显示时,它内部的层会准备好一个CGContextRef(图形上下文),然后调用delegate(这里就是UIView)的drawLayer:inContext:方法,并且传入已经准备好的CGContextRef对象。而UIView在drawLayer:inContext:方法中又会调用自己的drawRect:方法
* 平时在drawRect:中通过UIGraphicsGetCurrentContext()获取的就是由层传入的CGContextRef对象,在drawRect:中完成的所有绘图都会填入层的CGContextRef中,然后被拷贝至屏幕