一、UIView与CALayer的关系
UIView
属性持有layer
,layer
的代理是UIView
二、drawRect函数调用栈
1、询问UIView
是否实现了CALayerDelegate
的drawLayer:inContext:
代理方法,如果实现了就走drawLayer:inContext:
,没实现就走drawRect:
三、渲染流程
1、layer通过代理传递给UIView
四、CALayer调用流程
-
一、布局
1、[CALayer layerSublayers]
2、询问代理方法
3、[UIView layoutSubViews]
总结:如果实现了CALayerDelegate
的layoutSublayersOfLayer:
代理方法,就走layoutSublayersOfLayer:
,没实现就走layoutSubviews
-
二、绘制
1、[CALayer _display]
2、[UIView drawLayer:InContext:] 走自己的代码
3、[UIView drawRect:]
总结:如果实现了CALayerDelegate
的drawLayer: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.delegate
的layoutSublayersOfLayer:
;如果没有实现执行CALayer
父类的layoutSublayers
3、CALayer.delegate
的代理是UIView
,CALayer.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对象被返回时,会⽴立刻执⾏行行动作来响应本次属性修改
网友评论