mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 04:17:17 +00:00
feature: Weex APM
This commit is contained in:
@@ -18,9 +18,149 @@ UIView 绘制流程。
|
||||
|
||||
当调用 UIView `[UIView setNeedsDisplay]` 方法时,系统会立刻调用其 Layer 的同名方法 `[view.layer setNeedsDisplay]` 方法,之后相当于给当前 Layer 打上一个脏标记,之后会在当前 RunLoop 快要结束的时候才会调用 Layer 的 `[CALayer display]` 方法。然后进入当前 UIView 真正的绘制流程中。
|
||||
|
||||
其次,会判断 CALayer 的代理,有没有实现 `displayLayer:` 方法,如果没有实现,则进入系统的绘制流程中;如果实现了,则可能是异步绘制或者自定义渲染的实现。
|
||||
其次,会判断 CALayer 的代理,有没有实现 `displayLayer:` 方法
|
||||
|
||||
- 如果没有实现,则进入系统的绘制流程:比如:创建绘制上下文、调用 `drawInContext:`、生成内容并赋值给 `contents`
|
||||
- 如果实现了,则可能是异步绘制或者自定义渲染的实现。是**代理自定义绘制的入口**。代理可以在这个方法里直接设置`layer.contents`(比如异步绘制生成 UIImage 后赋值给`contents`),完全接管 layer 的内容渲染
|
||||
|
||||
|
||||
|
||||
Demo1:
|
||||
|
||||
自定义 View,不实现 `displayInContext` 方法
|
||||
|
||||
```objective-c
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface CustomDrawView : UIView
|
||||
@end
|
||||
|
||||
@implementation CustomDrawView
|
||||
|
||||
// 重写drawRect: —— 系统绘制流程的上层入口
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
// 1. 系统自动创建绘制上下文,这里可以直接获取
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
// 2. 绘制操作(对应系统流程的「调用drawInContext:」阶段)
|
||||
// 设置填充色为红色
|
||||
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
|
||||
// 绘制一个矩形
|
||||
CGContextFillRect(context, CGRectMake(20, 20, 100, 100));
|
||||
|
||||
NSLog(@"执行drawRect: → 底层对应系统调用CALayer的drawInContext:");
|
||||
}
|
||||
|
||||
// 关键:不实现 displayLayer: 代理方法
|
||||
// - (void)displayLayer:(CALayer *)layer {} // 注释掉,模拟「未实现」场景
|
||||
|
||||
@end
|
||||
```
|
||||
|
||||
在 ViewController 中使用
|
||||
|
||||
```objective-c
|
||||
#import "ViewController.h"
|
||||
#import "CustomDrawView.h"
|
||||
|
||||
@interface ViewController ()
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
// 1. 创建自定义View并添加到界面
|
||||
CustomDrawView *drawView = [[CustomDrawView alloc] initWithFrame:CGRectMake(50, 100, 150, 150)];
|
||||
drawView.backgroundColor = [UIColor lightGrayColor]; // 浅灰色背景,方便区分绘制区域
|
||||
[self.view addSubview:drawView];
|
||||
|
||||
// 2. 触发绘制(打脏标记,RunLoop阶段系统会执行layer.display)
|
||||
[drawView setNeedsDisplay];
|
||||
}
|
||||
|
||||
@end
|
||||
```
|
||||
|
||||
结果:屏幕上会显示「浅灰色背景 + 红色矩形」;控制台打印: `执行drawRect: → 底层对应系统调用CALayer的drawInContext:`;
|
||||
|
||||
分析:
|
||||
|
||||
- `[drawView setNeedsDisplay]` → 内部调用 `layer.setNeedsDisplay`,给 layer 打 “脏标记”
|
||||
- 当前 RunLoop 的 CATransaction 阶段,系统调用 `[layer display]`
|
||||
- layer 检查代理(CustomDrawView)有没有实现代理方法 → 未实现`-(void)displayLayer:(CALayer *)layer`;
|
||||
- 系统**自动创建绘制上下文** → 调用 `[layer drawInContext:]`(UIView 的`drawRect:`是对这个方法的封装,所以`drawRect:`被执行)
|
||||
- 系统将绘制结果生成位图 → 赋值给 `layer.contents`
|
||||
- 最终 layer 把`contents`内容渲染到屏幕
|
||||
|
||||
Demo2:
|
||||
|
||||
自定义 Layer,实现 `displatLayer:` 代理方法的 Layer
|
||||
|
||||
```objective-c
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface CustomLayer : CALayer
|
||||
@end
|
||||
|
||||
@implementation CustomLayer
|
||||
|
||||
// 重写CALayer的drawInContext: —— 系统绘制流程的核心方法
|
||||
- (void)drawInContext:(CGContextRef)ctx {
|
||||
// 系统创建的上下文会传入这个方法
|
||||
NSLog(@"系统调用drawInContext: → 进入核心绘制阶段");
|
||||
|
||||
// 绘制操作:画一个蓝色圆形
|
||||
CGContextSetFillColorWithColor(ctx, [UIColor blueColor].CGColor);
|
||||
CGContextFillEllipseInRect(ctx, CGRectMake(20, 20, 100, 100));
|
||||
}
|
||||
|
||||
@end
|
||||
```
|
||||
|
||||
在 VC 中使用
|
||||
|
||||
```objective-c
|
||||
#import "ViewController.h"
|
||||
#import "CustomLayer.h"
|
||||
|
||||
@interface ViewController ()
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
// 1. 创建自定义Layer
|
||||
CustomLayer *customLayer = [CustomLayer layer];
|
||||
customLayer.frame = CGRectMake(50, 250, 150, 150);
|
||||
customLayer.backgroundColor = [UIColor lightGrayColor].CGColor;
|
||||
[self.view.layer addSublayer:customLayer];
|
||||
|
||||
// 2. 触发绘制(打脏标记)
|
||||
[customLayer setNeedsDisplay];
|
||||
}
|
||||
|
||||
@end
|
||||
```
|
||||
|
||||
结果:屏幕上显示「浅灰色背景 + 蓝色圆形」;并且输出:`系统调用drawInContext: → 进入核心绘制阶段`
|
||||
|
||||
分析:
|
||||
|
||||
- 调用 CALayer 的 setNeedsDisplay 方法,内部会调用 display 方法
|
||||
- 系统会将其 CALayer 打上 dirty 标记
|
||||
- RunLoop 会在一次 loop 的末尾,提交 CATranscation。然后去绘制 layer 的 displayLayer 方法
|
||||
- 判断没有实现 displayLayer 方法,然后自动创建渲染上下文。
|
||||
- 然后调用 `drawInContext:(CGContextRef)ctx` ,方法的 ctx 参数就是系统自动创建的上下文对象
|
||||
- 该方法内创建的渲染内容,最后会合成一张 bitmap,最后交给 layer.contents 属性
|
||||
- 屏幕渲染 contents 内容
|
||||
|
||||
|
||||
Tips:`[UIView setNeedsDisplay]` 之后并不会立马调用 `[view.layer setNeedsDisplay]` 方法。要么手动触发 `[view.layer setNeedsDisplay]` 要么,调用一下 `-(void)drawRect:(CGRect)rect` 方法(即使是空实现也没关系)。
|
||||
|
||||
下面来个 Demo 展示下简单的异步绘制一个 String。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user