Refresh frame by frame with CADisplayLink
CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget: self
selector: @selector(update)];
[displayLink addToRunLoop: NSRunLoop.mainRunLoop
forMode: NSDefaultRunLoopMode];
In the refresh method, call setNeedsDisplay of the rendered UIView
- (void)update {
[self.vv setNeedsDisplay];
}
Under the rendered UIView subclass, inherit 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);
}
○ Remember to inherit drawRect
When we draw CALayer, we need to use the relevant information of UIView, which is stored in CGContextRef, and this information can only be used drawRect
after .
That is to say, after UIView calls drawRect, it will further call drawLayer. Therefore, when inheriting UIView, you must inherit and implement drawRect, so that drawLayer inheritance will be called.
○ CGContextClearRect
Used to clear the information drawn in the rectangle.
○ CGContextSaveGState/CGContextRestoreGState
Save and restore the context, called at the beginning and end of drawing a layer. to avoid breaking previous context.
○ CGContextTranslateCTM
The function of this function is to translate the drawing context along the x-axis and y-axis by the specified distance.
In this example, why is CGContextTranslateCTM called like this:
`CGContextTranslateCTM(ctx, 0, self.bounds.size.height);`
This CGContextScaleCTM
can .
CGContextTranslateCTM is used to set the starting area of screen drawing, which is used here (0, self.bounds.size.height)
to set the starting area of drawing at the bottom left of the screen.
○ CGContextScaleCTM
If you follow the setting of the previous line of code, the drawn area is obviously "out of the screen". So a second function is needed CGContextScaleCTM
, and you can see that the function is called like this:
CGContextScaleCTM(ctx, self.bounds.size.width / width, -self.bounds.size.height / height);
It can be seen that this function is used for screen stretching. The stretching ratio is fully stretched horizontally and vertically. This is easy to understand, but the key point is to pay attention to the second parameter:
-self.bounds.size.height / height
The second parameter is a negative value, which means that the drawn area will be stretched in reverse, so the picture will be flipped. After combining CGContextTranslateCTM, the drawing of the picture becomes from the lower left corner of the screen as the starting address of the vertical coordinates, drawing to the upper left corner of the screen.
○ CGColorSpaceCreateDeviceRGB/CGColorSpaceRelease
Used to create and release RGB color space objects. The created object will be CGBitmapContextCreate
used .
○ CGBitmapContextCreate/CGContextRelease
The graphics context function used to create and release the bitmap, through which the bitmap data is passed in.
○ CGBitmapContextCreateImage
Create a bitmap.
It should be noted that there is no need to release the bitmap here, because the reference will be used to draw UIView, and then it will enter the life cycle management of UIView.
○ CGContextDrawImage
A layer that renders a bitmap to a UIView.