用 CADisplayLink 做逐帧刷新
CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget: self
selector: @selector(update)];
[displayLink addToRunLoop: NSRunLoop.mainRunLoop
forMode: NSDefaultRunLoopMode];
刷新方法里,调用渲染的 UIView 的 setNeedsDisplay
- (void)update {
[self.vv setNeedsDisplay];
}
在渲染的 UIView 子类下,继承 drawLayer
// drawRect 也记得写上,否则失效
- (void)drawRect:(CGRect)rect {
[super drawRect: rect];
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextClearRect(ctx, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height));
CGContextSaveGState(ctx);
const int width = 320;
const int height = 640;
CGRect drawRect = CGRectMake(0, 0, width, height);
CGContextTranslateCTM(ctx, 0, self.bounds.size.height);
CGContextScaleCTM(ctx, self.bounds.size.width / width, -self.bounds.size.height / height);
uint32_t pixels[width * height] = { 0 };
for (size_t i = 0; i < width * height; ++i) {
pixels[height][width] = 0xffffffff;
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixels,
width,
height,
8,
width * 4,
colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
CGColorSpaceRelease(colorSpace);
CGImageRef imageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGContextDrawImage(ctx, drawRect, imageRef);
CGContextRestoreGState(ctx);
}
○ 记得继承 drawRect
当我们绘制 CALayer 时,需要使用 UIView 的相关信息,该信息被保存在 CGContextRef 中,而这个信息要调用了 drawRect
后才能使用。
也就是说,UIView 调用 drawRect 后才会进一步调用 drawLayer,因此继承 UIView 时,必须继承实现 drawRect,这样 drawLayer 继承才会被调用。
○ CGContextClearRect
用于清除矩形中绘制的信息。
○ CGContextSaveGState/CGContextRestoreGState
保存和恢复上下文,在绘制图层的开始和结束调用。以避免破坏之前的上下文。
○ CGContextTranslateCTM
该函数的作用是将绘图上下文沿x轴和y轴平移指定的距离。
在本例中,CGContextTranslateCTM 为什么是这么调用呢:
`CGContextTranslateCTM(ctx, 0, self.bounds.size.height);`
这个要配合后面的 CGContextScaleCTM
才能揭晓完整答案。
CGContextTranslateCTM 用于设置屏幕绘制的起始区域,这里用 (0, self.bounds.size.height)
,即将绘制的起始区域设置在屏幕左下方。
○ CGContextScaleCTM
如果按照上一行代码的设置,绘制的区域显然就“超出屏幕”了。所以需要第二个函数 CGContextScaleCTM
,可以看到函数是这么被调用的:
CGContextScaleCTM(ctx, self.bounds.size.width / width, -self.bounds.size.height / height);
这个函数可以看出是用于屏幕拉伸的,拉伸的比例是横纵向全拉伸满,这个很好理解,但是关键要注意第二个参数:
-self.bounds.size.height / height
第二个参数是负值,这意味着绘制的区域会做反向拉伸,于是画面会被翻转,结合 CGContextTranslateCTM 后,画面的绘制就变成从屏幕左下角作为纵向坐标的起始地址,绘制到屏幕的左上角。
○ CGColorSpaceCreateDeviceRGB/CGColorSpaceRelease
用于创建和释放 RGB 颜色空间对象。创建出来的对象会作为参数给 CGBitmapContextCreate
使用。
○ CGBitmapContextCreate/CGContextRelease
用于创建和释放位图的图形上下文函数,通过这个函数将位图数据传入。
○ CGBitmapContextCreateImage
创建位图。
需要注意的是,这里不需要释放位图,是因为该引用会被用于绘制 UIView,接下来它会进入 UIView 的生命周期管理。
○ CGContextDrawImage
将位图渲染到 UIView 的图层。