什么是Quartz2D?
Quartz 2D是一個二維繪圖引擎,同時支持iOS和Mac系統(tǒng)
- Quartz 2D能完成的工作
- 繪制圖形 : 線條\三角形\矩形\圓\弧等
- 繪制文字
- 繪制\生成圖片(圖像)
- 讀取\生成PDF
- 截圖\裁剪圖片
- 自定義UI控件
Quartz2D在iOS開發(fā)中的價值:
- 繪制一些系統(tǒng)UIKit框架中不好展示的內(nèi)容,例如餅圖
- 自定義一些控件
- 不添加UI控件的情況下,使UI內(nèi)容更豐富
- ……
iOS中,大部分控件都是Quartz2D繪制出來的
圖形上下文
[圖片上傳失敗...(image-534e23-1521165872369)]
圖形上下文就相當(dāng)于畫布,不同類型的畫布就是決定著畫得內(nèi)容將展示在哪里。
- Quartz2D提供了以下幾種類型的Graphics Context:
- Bitmap Graphics Context 位圖上下文,在這個上下文上繪制或者渲染的內(nèi)容,可以獲取成圖片(需要主動創(chuàng)建一個位圖上下文來使用,使用完畢,一定要銷毀)
- PDF Graphics Context
- Window Graphics Context
- Layer Graphics Context 圖層上下文,針對UI控件的上下文
- Printer Graphics Context
drawRect:
為什么要實(shí)現(xiàn)drawRect:方法才能繪圖到view上?
因?yàn)樵赿rawRect:方法中才能取得跟view相關(guān)聯(lián)的圖形上下文
drawRect:中取得的上下文
在drawRect:方法中取得上下文后,就可以繪制東西到view上
View內(nèi)部有個layer(圖層)屬性,drawRect:方法中取得的是一個Layer Graphics Context,因此,繪制的東西其實(shí)是繪制到view的layer上去了
View之所以能顯示東西,完全是因?yàn)樗鼉?nèi)部的layer
drawRect:方法的調(diào)用?
- 當(dāng)view第一次顯示到屏幕上時,系統(tǒng)會創(chuàng)建好一個跟當(dāng)前view相關(guān)的Layer上下文
- 系統(tǒng)會通過此上下文,在drawRect:方法中繪制好當(dāng)前view的內(nèi)容
- 主動讓view重繪內(nèi)容的時候,調(diào)用setNeedsDisplay或者setNeedsDisplayInRect:。我們主動調(diào)用drawRect:方法是無效的。
- 調(diào)用view的setNeedsDisplay或者setNeedsDisplayInRect:時。
- 注意:setNeedsDisplay和setNeedsDisplayInRect:方法調(diào)用后,屏幕并不是立即刷新,而是會在下一次刷新屏幕的時候把繪制的內(nèi)容顯示出來。
也正是系統(tǒng)會在調(diào)用這個方法之前創(chuàng)建一個與該view相關(guān)的上下文,才讓我們可以在drawRect:方法中繪制。注意:在其他地方拿不到view相關(guān)的上下文,所以不能實(shí)現(xiàn)繪制。
自定義view
如何利用Quartz2D繪制東西到view上?
- 首先,得有圖形上下文,因?yàn)樗鼙4胬L圖信息,并且決定著繪制到什么地方去
- 其次,那個圖形上下文必須跟view相關(guān)聯(lián),才能將內(nèi)容繪制到view上面
自定義view的步驟:
- 新建一個類,繼承自UIView
- 實(shí)現(xiàn)- (void)drawRect:(CGRect)rect方法,然后在這個方法中
- 取得跟當(dāng)前view相關(guān)聯(lián)的圖形上下文
- 繪制相應(yīng)的圖形內(nèi)容
- 利用圖形上下文將繪制的所有內(nèi)容渲染顯示到view上面
常用拼接路徑函數(shù)
獲取上下文
CGContextRef triangle = UIGraphicsGetCurrentContext();新建一個起點(diǎn)
void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)添加新的線段到某個點(diǎn)
void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)添加一個矩形
void CGContextAddRect(CGContextRef c, CGRect rect)添加一個橢圓
void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)添加一個圓弧
void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
常用繪制路徑函數(shù)
Mode參數(shù)決定繪制的模式
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)繪制空心路徑
void CGContextStrokePath(CGContextRef c)繪制實(shí)心路徑
void CGContextFillPath(CGContextRef c)
提示:一般以CGContextDraw、CGContextStroke、CGContextFill開頭的函數(shù),都是用來繪制路徑的
圖形上下文棧的操作
將當(dāng)前的上下文copy一份,保存到棧頂(那個棧叫做”圖形上下文?!?
void CGContextSaveGState(CGContextRef c)將棧頂?shù)纳舷挛某鰲?替換掉當(dāng)前的上下文
void CGContextRestoreGState(CGContextRef c)
矩陣操作
利用矩陣操作,能讓繪制到上下文中的所有路徑一起發(fā)生變化
縮放
void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)旋轉(zhuǎn)
void CGContextRotateCTM(CGContextRef c, CGFloat angle)平移
void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
繪圖的核心步驟:
- 獲得上下文
- 繪制/拼接繪圖路徑
- 將路徑添加到上下文
- 渲染上下文
記?。核械睦L圖,都是這個步驟,即使使用貝塞爾路徑,也只是對這個步驟進(jìn)行了封裝。對于繪圖而言,拿到上下文很關(guān)鍵。
貝塞爾路徑
就是UIKit框架中,對繪圖的封裝。實(shí)際操作起來,使用貝塞爾路徑,更為方便。
- 用法與CGContextRef類似,但是oc對其進(jìn)行了封裝,更加面向?qū)ο蟆?/li>
- 常用的方法:
返回一個描述橢圓的路徑:
+ (UIBezierPath *)bezierPathWithOvalInRect:(CGRect)rect;設(shè)置起始點(diǎn):
- (void)moveToPoint:(CGPoint)point;添加直線到一點(diǎn):
- (void)addLineToPoint:(CGPoint)point;三次貝塞爾曲線:
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
[圖片上傳失敗...(image-f06941-1521165872367)]
-
貝塞爾曲線:
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;[圖片上傳失敗...(image-c02bb8-1521165872365)]
-
繪制圓弧:
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;[圖片上傳失敗...(image-26cc2-1521165872365)]
封閉閉路徑:
- (void)closePath;
裁剪核心代碼
// 開啟一個位圖(圖片)上下文
//size:上下文尺寸
//opaque:不透明。一般是透明的,所以設(shè)置為NO
//scale:縮放,如果不縮放,設(shè)置為0就好
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
// 描述圓形的路徑
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
// 把圓形路徑設(shè)置裁剪區(qū)域(將區(qū)域外的內(nèi)容裁剪掉,是現(xiàn)實(shí)區(qū)域內(nèi)的內(nèi)容)
[path addClip];
// 繪制圖片(先設(shè)置裁剪區(qū)域,再裁剪,才會有效果)
[image drawAtPoint:CGPointZero];
// 從上下文中內(nèi)容生成一張圖片
image = UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉上下文(一定不要忘了關(guān)閉自己開啟的上下文)
UIGraphicsEndImageContext();
截屏核心代碼
// 開啟一個跟屏幕一樣大的尺寸的上下文
UIGraphicsBeginImageContextWithOptions(caputeView.bounds.size, NO, 0);
// 獲取自己創(chuàng)建的位圖上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// view之所以你能顯示內(nèi)容,是因?yàn)橛袌D層,因此只要把圖層畫到上下文
// 圖層只能渲染,不能繪制
[caputeView.layer renderInContext:ctx];
// 從上下文中生成一張新的圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉上下文
UIGraphicsEndImageContext();
作者:Ljson
鏈接:http://www.itdecent.cn/p/0e785269dccc
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。