CoreGraphics之CGContextSaveGState与UIGraphicsPushContext
轉至:https://www.jianshu.com/p/be38212c0f79
CoreGraphics與UIKit
這邊從iOS繪圖教程 提取一些重要的內容。
Core Graphics Framework是一套基于C的API框架,使用了Quartz作為繪圖引擎。iOS支持兩套圖形API族:Core Graphics/QuartZ 2D 和OpenGL ES。
Core Graphics API所有的操作都在一個上下文中進行。所以在繪圖之前需要獲取該上下文并傳入執行渲染的函數中。如果你正在渲染一副在內存中的圖片,此時就需要傳入圖片所屬的上下文。獲得一個圖形上下文是我們完成繪圖任務的第一步,你可以將圖形上下文理解為一塊畫布。如果你沒有得到這塊畫布,那么你就無法完成任何繪圖操作。當然,有許多方式獲得一個圖形上下文,這里我介紹兩種最為常用的獲取方法。
創建一個圖片類型的上下文。調用UIGraphicsBeginImageContextWithOptions函數就可獲得用來處理圖片的圖形上下文。利用該上下文,你就可以在其上進行繪圖,并生成圖片。調用UIGraphicsGetImageFromCurrentImageContext函數可從當前上下文中獲取一個UIImage對象。記住在你所有的繪圖操作后別忘了調用UIGraphicsEndImageContext函數關閉圖形上下文。
利用cocoa為你生成的圖形上下文。當你子類化了一個UIView并實現了自己的drawRect:方法后,一旦drawRect:方法被調用,Cocoa就會為你創建一個圖形上下文,此時你對圖形上下文的所有繪圖操作都會顯示在UIView上。
判斷一個上下文是否為當前圖形上下文需要注意的幾點:
作為初學者,很容易被UIKit和Core Graphics兩個支持繪圖的框架迷惑。
UIKit
像UIImage、NSString(繪制文本)、UIBezierPath(繪制形狀)、UIColor都知道如何繪制自己。這些類提供了功能有限但使用方便的方法來讓我們完成繪圖任務。一般情況下,UIKit就是我們所需要的。
使用UiKit,你只能在當前上下文中繪圖,所以如果你當前處于UIGraphicsBeginImageContextWithOptions函數或drawRect:方法中,你就可以直接使用UIKit提供的方法進行繪圖。如果你持有一個context:參數,那么使用UIKit提供的方法之前,必須將該上下文參數轉化為當前上下文。幸運的是,調用UIGraphicsPushContext 函數可以方便的將context:參數轉化為當前上下文,記住最后別忘了調用UIGraphicsPopContext函數恢復上下文環境。
Core Graphics
這是一個繪圖專用的API族,它經常被稱為QuartZ或QuartZ 2D。Core Graphics是iOS上所有繪圖功能的基石,包括UIKit。
使用Core Graphics之前需要指定一個用于繪圖的圖形上下文(CGContextRef),這個圖形上下文會在每個繪圖函數中都會被用到。如果你持有一個圖形上下文context:參數,那么你等同于有了一個圖形上下文,這個上下文也許就是你需要用來繪圖的那個。如果你當前處于UIGraphicsBeginImageContextWithOptions函數或drawRect:方法中,并沒有引用一個上下文。為了使用Core Graphics,你可以調用UIGraphicsGetCurrentContext函數獲得當前的圖形上下文。
stackoverflow的問題
在stackoverflow上,有這樣一個問題CGContextSaveGState vs UIGraphicsPushContext問了兩者區別,這里列一下高票答案:
UIGraphicsPushContext(context) pushes context onto a stack of CGContextRefs (making context the current drawing context), whereas CGContextSaveGState(context) pushes the current graphics state onto the stack of graphics states maintained by context. You should use UIGraphicsPushContext if you need to make a new CGContextRef the current drawing context, and you should use CGContextSaveGState when you're working with one graphics context and just want to save, for example: the current transform state, fill or stroke colors, etc.
翻譯一下就是:
UIGraphicsPushContext(context)將context壓到一個CGContextRefs(使得context成為current context)的棧中。而CGContextSaveGState(context)將當前繪制狀態壓到一個context維護的繪制狀態的棧中。你可以使用UIGraphicsPushContext當你需要在當前的context去創建一個新的CGContextRef,同時你可以使用CGContextSaveGState當你在處理一個繪制context并且只是想保存的它的時候。比如:當前的變換狀態,填充或者線條顏色等。
以上答案其實就是在說:
實例
CGContextSaveGState
我們這里用一段實際代碼:
-(void)drawRect:(CGRect)rect{CGContextRef ctx=UIGraphicsGetCurrentContext();[[UIColor redColor] setStroke]; //紅色 CGContextSaveGState(UIGraphicsGetCurrentContext());CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 50, 50));CGContextSetLineWidth(ctx, 10);[[UIColor yellowColor] setStroke]; //黃色 CGContextStrokePath(ctx);CGContextRestoreGState(UIGraphicsGetCurrentContext());CGContextAddEllipseInRect(ctx, CGRectMake(200, 100, 50, 50)); //紅色 CGContextStrokePath(ctx); }?
運行一下看結果:
可以看到,CGContextSaveGState存儲下來了當前紅色和默認的線條狀態,然后切換顏色到黃色和10粗度的線條畫圈,然后在CGContextRestoreGState恢復到了紅色和默認的線條狀態進行畫圈,這個就是存儲當前繪制狀態的意思。
UIGraphicsPushContext
同樣用一段實際代碼:
- (void)viewDidLoad {[super viewDidLoad];CALayer *layer=[CALayer layer];layer.bounds=CGRectMake(0, 0, 300, 300);layer.position=CGPointMake(100, 100);layer.delegate=self;[layer setNeedsDisplay];[self.view.layer addSublayer:layer]; }-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{UIImage *image = [UIImage imageNamed:@"test.jpg"];UIGraphicsPushContext(ctx);[image drawInRect:CGRectMake(0, 0, 300, 300)];UIGraphicsPopContext(); }運行看一下結果:
如果你將UIGraphicsPushContext(ctx);與UIGraphicsPopContext();刪去的話,是無法進行繪制的。
原因是,UIKit的繪制必須在當前的上下文中繪制,而UIGraphicsPushContext可以將當前的參數context轉化為可以UIKit繪制的上下文,進行繪制圖片。
總結
CGContextSaveGState是壓棧當前的繪制狀態,而UIGraphicsPushContext:壓棧當前的繪制對象,生成新的繪制圖層。對于UIGraphicsPushContext的使用,很多都是與UIKit配合使用,更詳細的對于CoreGraphics的介紹,可以參考iOS繪圖教程 。
參考資料
1.CGContextSaveGState vs UIGraphicsPushContext
2.iOS --- CoreGraphics中三種繪圖context切換方式的區別
3.iOS core graphic使用分析
4.iOS繪圖教程?|?iOS繪圖教程
總結
以上是生活随笔為你收集整理的CoreGraphics之CGContextSaveGState与UIGraphicsPushContext的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RHEL6.2手动封装rpm源码包安装星
- 下一篇: TCP/IP学习(30)——L2数据链路