美文网首页
UIView&CALayer

UIView&CALayer

作者: Code_人生 | 来源:发表于2019-10-08 16:43 被阅读0次

    一、UIView与CALayer的关系

    UIView属性持有layerlayer的代理是UIView

    二、drawRect函数调用栈

    1、询问UIView是否实现了CALayerDelegatedrawLayer:inContext:代理方法,如果实现了就走drawLayer:inContext:,没实现就走drawRect:

    三、渲染流程

    1、layer通过代理传递给UIView

    四、CALayer调用流程

    • 一、布局
      1、[CALayer layerSublayers]
      2、询问代理方法
      3、[UIView layoutSubViews]
      总结:如果实现了CALayerDelegatelayoutSublayersOfLayer:代理方法,就走layoutSublayersOfLayer:,没实现就走layoutSubviews

    • 二、绘制
      1、[CALayer _display]
      2、[UIView drawLayer:InContext:] 走自己的代码
      3、[UIView drawRect:]
      总结:如果实现了CALayerDelegatedrawLayer:inContext:代理方法,就走drawLayer:inContext:,没实现就走drawRect:

    #import "CustomView.h"
    
    @interface CustomView ()<CALayerDelegate>
    
    @end
    
    @implementation CustomView
    
    #pragma mark -- 布局
    - (void)layoutSubviews {
        NSLog(@"%s",__func__);
    }
    
    //如果实现了CALayerDelegate的layoutSublayersOfLayer:代理方法,就走layoutSublayersOfLayer:,没实现就走layoutSubviews
    - (void)layoutSublayersOfLayer:(CALayer *)layer {
        NSLog(@"%s",__func__);
    }
    
    #pragma mark -- 绘制
    - (void)drawRect:(CGRect)rect {
        NSLog(@"%s",__func__);
    }
    
    //如果实现了CALayerDelegate的drawLayer:inContext:代理方法,就走drawLayer:inContext:,没实现就走drawRect:
    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
        NSLog(@"%s",__func__);
    }
    
    @end
    

    五、模拟系统UIView与CALayer

    布局
    1、CALayer调用- (void)layoutSublayers{}
    2、判断CALayer.delegate,是否实现了layoutSublayersOfLayer:,如果实现了执行CALayer.delegatelayoutSublayersOfLayer:;如果没有实现执行CALayer父类的layoutSublayers
    3、CALayer.delegate的代理是UIViewCALayer.delegate执行- (void)layoutSublayersOfLayer:(CALayer *)layer{}
    4、layoutSublayersOfLayer:中调用 - (void)layoutSubviews{}

    绘制
    5、CALayer调用- (void)display{}
    6、[self.delegate performSelector:@selector(createContext)],调用UIView的- (CGContextRef)createContext{}
    7、[self drawInContext:context],调用UIView- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{};如果UIView没有实现- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{},那就调用UIView- (void)drawRect:(CGRect)rect {}
    8、[self.delegate displayLayer:self],调用UIView- (void)displayLayer:(CALayer *)layer{}
    9、[self.delegate performSelector:@selector(closeContext)],调用UIView- (void)closeContext{}

    • LGView.h
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface LGView : UIView
    
    - (CGContextRef)createContext;
    
    - (void)closeContext;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    • LGView.m
    #import "LGView.h"
    #import "LGLayer.h"
    
    @implementation LGView
    
    
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    - (void)drawRect:(CGRect)rect {
        // Drawing code, 绘制的操作, BackingStore(额外的存储区域产于的) -- GPU
    }
    
    //子视图的布局
    - (void)layoutSubviews{
        [super layoutSubviews];
    }
    
    + (Class)layerClass{
        return [LGLayer class];
    }
    
    - (void)layoutSublayersOfLayer:(CALayer *)layer{
         [self layoutSubviews];
    }
    
    - (CGContextRef)createContext{
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.layer.opaque, self.layer.contentsScale);
        CGContextRef context = UIGraphicsGetCurrentContext();
        return context;
    }
    
    
    
    - (void)layerWillDraw:(CALayer *)layer{
        //绘制的准备工作,do nontihing
    }
    
    //绘制的操作
    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
        [[UIColor redColor] set];
           //Core Graphics
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(self.bounds.size.width / 2- 20, self.bounds.size.height / 2- 20, 40, 40)];
        CGContextAddPath(ctx, path.CGPath);
        CGContextFillPath(ctx);
    }
    
    //layer.contents = (位图)
    - (void)displayLayer:(CALayer *)layer{
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        dispatch_async(dispatch_get_main_queue(), ^{
            layer.contents = (__bridge id)(image.CGImage);
        });
    }
    
    - (void)closeContext{
        UIGraphicsEndImageContext();
    }
    
    @end
    
    • LGLayer.m
    #import "LGLayer.h"
    
    @implementation LGLayer
    
    //前面断点调用写下的代码
    - (void)layoutSublayers{
        if (self.delegate && [self.delegate respondsToSelector:@selector(layoutSublayersOfLayer:)]) {
            //UIView
            [self.delegate layoutSublayersOfLayer:self];
        }else{
            [super layoutSublayers];
        }
    }
    
    
    //绘制流程的发起函数
    - (void)display{
        
        // Graver 实现思路
    
        CGContextRef context = (__bridge CGContextRef)([self.delegate performSelector:@selector(createContext)]);
        
        [self.delegate layerWillDraw:self];
        
        [self drawInContext:context];
        
        [self.delegate displayLayer:self];
    
        [self.delegate performSelector:@selector(closeContext)];
    }
    
    @end
    

    六、隐式动画和显示动画

    • 隐式动画
      nil:⼿手动创建并添加到视图上的CALayer或其⼦子类在属性修改时,没有获取到具体的修改⾏行行为。此时被 修改的属性会被CATransaction记录,最终在下⼀一个runloop的回调中⽣生成动画来响应本次属性修改。 由于这个过程⾮非开发者主动完成的,因此这种动画被称作隐式动画
    • 显示动画
      CAAction的⼦子类:如果返回的是CAAction对象,会直接开始动画来响应图层属性的修改。⼀一般返回的对 象多为CABasicAnimation类型,对象中包装了了动画时⻓长、动画初始/结束状态、动画时间曲线等关键 信息。当CAAction对象被返回时,会⽴立刻执⾏行行动作来响应本次属性修改

    相关文章

      网友评论

          本文标题:UIView&CALayer

          本文链接:https://www.haomeiwen.com/subject/gpvvuctx.html