CoreGraphics的使用过程中,经常会遇到绘图context切换的操作,一般使用用到CGContextSaveGState/CGContextRestoreGState,UIGraphicsPushContext/UIGraphicsPopContext,UIGraphicsBeginImageContext/UIGraphicsEndImageContext这三对方法。
它们的区别如下:
CGContextSaveGState/CGContextRestoreGState用于记录和恢复已存储的绘图context。
[[UIColor redColor] setStroke]; //画笔红色
CGContextSaveGState(UIGraphicsGetCurrentContext()); //记录上下文的当前状态
[[UIColor blackColor] setStroke]; //画笔黑色
CGContextRestoreGState(UIGraphicsGetCurrentContext()); //恢复之前记录的上下文状态
UIRectFill(CGRectMake(10, 10, 100, 100)); //绘制红色矩形
UIGraphicsPushContext/UIGraphicsPopContext的作用就完全不同了,而是完全地切换绘图context。使用场景是:
先看一段代码:
const CGFloat Scale = [UIScreen mainScreen].scale;
GLsizei width = view.layer.bounds.size.width * Scale;
GLsizei height = view.layer.bounds.size.height * Scale;
GLubyte *imageData = (GLubyte *)calloc(width * height * 4, sizeof(GLubyte));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextScaleCTM(context, Scale, Scale);
UIGraphicsPushContext(context);
{
[view drawViewHierarchyInRect:view.layer.bounds afterScreenUpdates:NO];
}
UIGraphicsPopContext();
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
free(texturePixelBuffer);
以上代码的步骤为:
注意步骤2,因为必须调用UIKit中的绘图方法,所以才需要用到UIGraphicsPushContext/UIGraphicsPopContext。类似的UIKit方法还有
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; // 将当前layer渲染到image context中
// 绘制贝塞尔曲线
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 100));
[[UIColor blueColor] setFill];
[p fill];
这两种方法也是iOS中常见的截屏方法,但截取的图像有时未必足够清晰。
如果想在切换绘图context后,继续使用CoreGraphics绘图(而非UIKit),则不需要使用UIGraphicsPushContext/UIGraphicsPopContext。因为CoreGraphics已将绘图context视为参数。使用场景是:
例如,使用如下方法即可在一个绘图步骤中,切换到一个新的绘图context,完成截取view中图像的操作,然后再恢复之前的绘图步骤。
因新的绘图操作是使用UIGraphicsGetImageFromCurrentImageContext()截图,所以仍是CoreGraphics操作,因此不需要使用UIGraphicsPushContext/UIGraphicsPopContext。
// 绘图中
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageView.image = snapshot;
// 继续绘图
类似的使用方法还有:
// 绘图中
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
CGContextRef newContext = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(newContext, CGRectMake(0, 0, 100, 100));
CGContextSetFillColorWithColor(newContext, [UIColor blueColor].CGColor);
CGContextFillPath(newContext);
UIGraphicsEndImageContext();
// 继续绘图
注意,绘图context切换的关键是:要看切换新的绘图context后,是要继续使用CoreGraphics绘制图形,还是要使用UIKit。