CALayer04-自定义图层

一、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中,然后被拷贝至屏幕

原文地址:https://www.cnblogs.com/yipingios/p/4501460.html