什么是Quartz2D?
簡(jiǎn)單來(lái)說(shuō)尘应,Quartz2D是用C語(yǔ)言封裝的二維繪圖引擎,同時(shí)支持iOS和Mac系統(tǒng),利用Quartz2D挽霉,我們可以完成以下工作:
- 繪制圖形 : 線條\三角形\矩形\圓\弧等
- 繪制文字
- 繪制\生成圖片(圖像)
- 讀取\生成PDF
- 截圖\裁剪圖片
- 自定義UI控件
學(xué)習(xí)Quartz2D的價(jià)值在哪里
雖然Quartz2D屬于偏底層的API翩蘸,并且UIKit已經(jīng)把我們經(jīng)常使用的控件封裝好所意,但是,面對(duì)一些自定義控件催首,復(fù)雜的控件扶踊,UIKit就顯得有些無(wú)力了。
學(xué)好Quartz2D郎任,我們就可以:
- 繪制一些系統(tǒng)UIKit框架中不好展示的內(nèi)容秧耗,例如餅圖,環(huán)形進(jìn)度條舶治,統(tǒng)計(jì)圖表
- 自定義一些控件
- 不添加UI控件的情況下分井,使UI內(nèi)容更豐富
- ……
在iOS中,我們所看見的大部分控件都是利用Quartz2D繪制出來(lái)的歼疮。
什么是圖形上下文
簡(jiǎn)單來(lái)說(shuō)杂抽,圖形上下文就相當(dāng)于一塊畫布,我們可以在這塊畫布上畫任何我們想要的內(nèi)容韩脏,最后展示在View上缩麸。
然而,這個(gè)畫布一定要在drawRect:方法里面去獲取赡矢,實(shí)現(xiàn)才有效杭朱,下面就具體講下這個(gè)方法阅仔。
drawRect:
為什么要實(shí)現(xiàn)drawRect:方法才能繪圖到view上?
因?yàn)樵赿rawRect:方法中才能取得跟view相關(guān)聯(lián)的圖形上下文
在drawRect:方法中取得上下文后弧械,就可以繪制東西到view上
drawRect如何繪圖到View上
View內(nèi)部有個(gè)layer(圖層)屬性八酒,drawRect:方法中取得的是一個(gè)Layer Graphics Context,因此刃唐,繪制的東西其實(shí)是繪制到view的layer上去了
View之所以能顯示東西羞迷,完全是因?yàn)樗鼉?nèi)部的layer
drawRect:方法如何調(diào)用的
- 當(dāng)view第一次顯示到屏幕上時(shí),系統(tǒng)會(huì)創(chuàng)建好一個(gè)跟當(dāng)前view相關(guān)的Layer上下文
- 系統(tǒng)會(huì)通過(guò)此上下文画饥,在drawRect:方法中繪制好當(dāng)前view的內(nèi)容
- 主動(dòng)讓view重繪內(nèi)容的時(shí)候衔瓮,調(diào)用setNeedsDisplay或者setNeedsDisplayInRect:。我們主動(dòng)調(diào)用drawRect:方法是無(wú)效的抖甘。
- 調(diào)用view的setNeedsDisplay或者setNeedsDisplayInRect:時(shí)
- 注意:setNeedsDisplay和setNeedsDisplayInRect:方法調(diào)用后热鞍,屏幕并不是立即刷新,而是會(huì)在下一次刷新屏幕的時(shí)候把繪制的內(nèi)容顯示出來(lái)衔彻。
也正是系統(tǒng)會(huì)在調(diào)用這個(gè)方法之前創(chuàng)建一個(gè)與該view相關(guān)的上下文薇宠,才讓我們可以在drawRect:方法中繪制。
注意:在其他地方拿不到view相關(guān)的上下文艰额,所以不能實(shí)現(xiàn)繪制澄港。
自定義View的步驟
如何利用Quartz2D繪制東西到view上?
- 新建一個(gè)類悴晰,繼承自UIView
- 實(shí)現(xiàn)- (void)drawRect:(CGRect)rect方法慢睡,然后在這個(gè)方法中
- 取得跟當(dāng)前view相關(guān)聯(lián)的圖形上下文
- 繪制相應(yīng)的圖形內(nèi)容
- 利用圖形上下文將繪制的所有內(nèi)容渲染顯示到view上面
下面我就介紹如何使用Quartz2D畫各種圖形。
實(shí)現(xiàn)代碼
寫文字
NSString *text = @"我要寫的文字";
UIFont *font = [UIFont boldSystemFontOfSize:20.f];
UIColor *color = [UIColor purpleColor];
NSDictionary *attributes = @{NSForegroundColorAttributeName:color,
NSFontAttributeName:font};
[text drawInRect:CGRectMake(10, 20, 80, 20) withAttributes:attributes];
畫圓
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);//設(shè)置畫筆顏色
CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);//設(shè)置填充顏色
CGContextSetLineWidth(context, 5.f);//線的寬度
CGContextAddArc(context, 100, 200, 15, 0, M_PI * 2, 0);//添加一個(gè)圓
CGContextDrawPath(context, kCGPathStroke);//繪制路徑
void CGContextAddArc(CGContextRef c,CGFloat x, CGFloat y,CGFloat radius,CGFloat startAngle,CGFloat endAngle, int clockwise)
- x,y為圓點(diǎn)坐標(biāo)
- radius半徑
- startAngle為開始的弧度
- endAngle為 結(jié)束的弧度
- clockwise 0為順時(shí)針铡溪,1為逆時(shí)針
- ps:1弧度=180°/π (≈57.3°) 度=弧度×180°/π 360°=360×π/180 =2π 弧度
CGContextDrawPath(context, kCGPathStroke)
這個(gè)方法的第二個(gè)參數(shù)是一個(gè)枚舉
- kCGPathFill 填充非零繞數(shù)規(guī)則,
- kCGPathEOFill 表示用奇偶規(guī)則,
- kCGPathStroke 路徑,
- kCGPathFillStroke 路徑填充,
- kCGPathEOFillStroke 表示描線漂辐,不是填充
如果你只想畫一個(gè)圓而不需要填充就用kCGPathStroke
,如果你不想要路徑,只想填充就用kCGPathFil
棕硫,如果你既要路徑又要填充就要使用kCGPathFillStroke
髓涯。
如果只是繪制路徑還可以使用這個(gè)方法
void CGContextStrokePath(CGContextRef c)
如果只是填充還可以使用這個(gè)方法
void CGContextFillPath(CGContextRef c)
畫直線
CGPoint aPoints[2];//坐標(biāo)點(diǎn)
aPoints[0] =CGPointMake(100, 80);//坐標(biāo)1
aPoints[1] =CGPointMake(130, 80);//坐標(biāo)2
CGContextAddLines(context, aPoints, 2);//添加線
CGContextDrawPath(context, kCGPathStroke); //根據(jù)坐標(biāo)繪制路徑
CGContextAddLines(CGContextRef c, const CGPoint points[],size_t count)
points[]坐標(biāo)數(shù)組,count點(diǎn)個(gè)數(shù)
如果你不需要畫折線哈扮,還有一種簡(jiǎn)單的寫法
CGContextMoveToPoint(context, 100, 80); //移動(dòng)到坐標(biāo)1
CGContextAddLineToPoint(context, 130, 80);//從坐標(biāo)一畫線到坐標(biāo)2
畫矩形
CGRect rect1 = CGRectMake(100, 120, 20, 20);//創(chuàng)建一個(gè)rect
CGContextAddRect(context, rect1);//添加一個(gè)矩形
CGContextStrokePath(context);//繪制路徑
//如果要填充要使用另外一個(gè)方法CGContextFillPath(context);
對(duì)于矩形纬纪,我們可以使用一下兩個(gè)簡(jiǎn)便方法繪制
繪制空心矩形(不填充)
void CGContextStrokeRect(CGContextRef __nullable c, CGRect rect)
繪制實(shí)心矩形(填充)
void CGContextFillRect(CGContextRef __nullable c, CGRect rect)
畫扇形
畫扇形,也就畫圓滑肉,只不過(guò)是設(shè)置角度的大小包各,形成一個(gè)扇形。
下面代碼以10為半徑圍繞圓心畫指定角度扇形靶庙。
CGContextMoveToPoint(context, 160, 180);//移到起始點(diǎn)问畅,即扇形的圓心
CGContextAddArc(context, 160, 180, 30, -60 * M_PI / 180, -120 * M_PI / 180, 1);//添加扇形
CGContextClosePath(context);//閉合路徑(畫扇形一定要有起始點(diǎn)和終點(diǎn),且要閉合)
CGContextDrawPath(context, kCGPathFillStroke); //繪制路徑
畫橢圓
CGContextAddEllipseInRect(context, CGRectMake(160, 180, 20, 8)); //橢圓
CGContextDrawPath(context, kCGPathFillStroke);
畫三角形
畫三角形只要三個(gè)點(diǎn)就行跟畫一條線方式一樣,把三點(diǎn)連接起來(lái)
CGPoint sPoints[3];//坐標(biāo)點(diǎn)
sPoints[0] =CGPointMake(100, 220);//坐標(biāo)1
sPoints[1] =CGPointMake(130, 220);//坐標(biāo)2
sPoints[2] =CGPointMake(130, 160);//坐標(biāo)3
CGContextAddLines(context, sPoints, 3);//添加線
CGContextClosePath(context);//封起來(lái)
CGContextDrawPath(context, kCGPathFillStroke); //根據(jù)坐標(biāo)繪制路徑
畫貝塞爾曲線
二次曲線
CGContextMoveToPoint(context, 120, 300);//設(shè)置Path的起點(diǎn)
CGContextAddQuadCurveToPoint(context,190, 310, 120, 390);//設(shè)置貝塞爾曲線的控制點(diǎn)坐標(biāo)和終點(diǎn)坐標(biāo)
CGContextStrokePath(context);
三次曲線函數(shù)
CGContextMoveToPoint(context, 200, 300);//設(shè)置Path的起點(diǎn)
CGContextAddCurveToPoint(context,250, 280, 250, 400, 280, 300);//設(shè)置貝塞爾曲線的控制點(diǎn)坐標(biāo)(2個(gè))和終點(diǎn)坐標(biāo)
CGContextStrokePath(context);
畫圖片
UIImage *image = [UIImage imageNamed:@"apple.jpg"];
[image drawInRect:CGRectMake(60, 340, 20, 20)];//在坐標(biāo)中畫出圖片
圖形上下文棧的操作
將當(dāng)前的上下文copy一份,保存到棧頂(那個(gè)棧叫做”圖形上下文椈つ罚”)
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)
想了解更多內(nèi)容,可以點(diǎn)擊以下鏈接: