
我們可以看到它位于Media Layer(Media Layer:媒體層提供應(yīng)用中視聽方面的技術(shù),如圖形圖像相關(guān)的CoreGraphics,CoreImage,GLKit,OpenGL ES,CoreText,ImageIO等等。聲音技術(shù)相關(guān)的CoreAudio,OpenAL,AVFoundation,視頻相關(guān)的CoreMedia,Media Player框架,音視頻傳輸?shù)腁irPlay框架等)。
一、系統(tǒng)的繪圖框架都有哪些

- UIKit
我們平常最常用的就是UIKit,其底層是依賴CoreGraphics實現(xiàn)的,而且絕大多數(shù)的圖形界面也都是由UIKit完成,并且UIImage、NSString、UIBezierPath、UIColor等都知道如何繪制自己,也提供了一些方法來滿足我們常用的繪圖需求。 - CoreGraphics
主要的繪圖系統(tǒng),常用于繪制自定義視圖,純C的API,使用Quartz2D做引擎。Core Graphics數(shù)據(jù)結(jié)構(gòu)和函數(shù)可以通過CG前綴來識別。 - Core Animation
提供了強大的2D和3D動畫服務(wù),它也與UIView高度集成。 - Core Image
提供了非??斓膱D片過濾方式,比如模糊,切圖,銳化,扭曲和其他一些你能想象的變形效果。 - OpenGL-ES
主要用于游戲繪制,但它是一套編程規(guī)范,具體由設(shè)備制造商實現(xiàn)。
二、繪圖方式
1. 繪圖周期 (個人理解還不透徹,會繼續(xù)學(xué)習(xí)更新)
首先我們需要了解繪圖周期,因為都是在繪圖周期中進(jìn)行的。
- iOS會在運行循環(huán)中整合所有繪圖請求,并在RunLoop將要結(jié)束時,一次將他們繪制出來。
所以,不能在子線程中繪制,也不能進(jìn)行過于復(fù)雜的操作(否則會造成主線程卡頓)。
2. 繪圖方式
- 視圖繪制
調(diào)用UIView的drawRect方法進(jìn)行繪制。如果調(diào)用一個view的setNeedsDisplay方法,那么該視圖會被標(biāo)記為需要重新繪制,會在下個繪制周期中重新繪制(此時會自動調(diào)用drawRect方法)。
drawRect被觸發(fā):
1.會在第一次被add到父視圖上;2.還有調(diào)用setNeedsDisplay。
- 視圖布局
調(diào)用UIView的layoutSubviews進(jìn)行布局。如果調(diào)用一個view的setNeedsLayout方法,那么該view會被標(biāo)記為需要重新布局,UIKit會自動調(diào)用layoutSubviews方法及其子視圖的layoutSubviews方法。
在繪圖時,我們應(yīng)該多使用布局,少使用繪制,因為布局使用的是GPU,繪制使用的是CPU。GPU對于圖形處理有優(yōu)勢,CPU要處理的事情較多,且不擅長圖形處理。
三、準(zhǔn)備工作
在介紹具體方法之前,我們需要知道,iOS的繪圖必須在上下文中繪制,所以繪制前必須先獲取上下文。如果是繪制圖片,則先獲取一個圖片上下文,如果是其他視圖,就需要獲取一個非圖片上下文。上下文可以理解為畫布,在上面進(jìn)行繪圖。
1.上下文
- context(在drawRect方法中獲?。?br> 圖形上下文(注意不是圖片),可以通過UIGraphicsGetCurrentContext獲取。
- imageContext (不必在drawRect方法中)
圖片上下文,通過UIGraphicsBeginImageContextWithOptions:獲取一個圖片上下文,然后繪制完成后,調(diào)用UIGraphicsGetImageFromCurrentImageContext獲取繪制的圖片,最后要記得關(guān)閉圖片上下文UIGraphicsEndImageContext。
四、具體繪圖方法
由于iOS常見的繪圖框架有兩種,所以繪圖的方法也有多種,我們介紹幾種常見的方法。
1.通過圖片類型的上下文
圖片類型的上下文,不需要在drawRect方法中,在普通的oc方法中就可以進(jìn)行繪制:
使用CoreGraphics實現(xiàn):
// 獲取圖片上下文
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0);
// 繪圖
CGContextRef con = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100));
CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
CGContextFillPath(con);
// 從圖片上下文中獲取繪制的圖片
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉圖片上下文
UIGraphicsEndImageContext();
使用UIKit方式實現(xiàn)
// 獲取圖片上下文
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0);
// 繪圖
UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
[[UIColor blueColor] setFill];
[p fill];
// 從圖片上下文中獲取繪制的圖片
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉圖片上下文
UIGraphicsEndImageContext();
2.通過drawRect:方法
在view的drawRect方法中,實現(xiàn)重新繪制:
使用CoreGraphics實現(xiàn):
- (void) drawRect: (CGRect) rect {
CGContextRef con = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100));
CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor);
CGContextFillPath(con);
}
使用UIKit方式實現(xiàn)
- (void) drawRect: (CGRect) rect {
UIBezierPath* p = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0,100,100)];
[[UIColor blueColor] setFill];
[p fill];
}
3.通過drawLayer:inContext:
待續(xù)。。。
五、CoreGraphics具體如何使用
上邊內(nèi)容大多是告訴我們CoreGraphics的使用場景以及系統(tǒng)相關(guān)內(nèi)容介紹,下邊我們來看看具體CoreGraphics是如何使用的
1.具體步驟:
- 先在drawRect方法中獲得上下文context(或通過imageContext);
- 繪制圖形(線,圖形,圖片等);
- 設(shè)置一些修飾屬性;
- 渲染到上下文,完成繪圖。
show me code
#import "CustomView.h"
@implementation CustomView
- (void)drawRect:(CGRect)rect
{
// 1.獲取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// --------------------------實心圓
// 2.畫圖
CGContextAddEllipseInRect(ctx, CGRectMake(10, 10, 50, 50));
[[UIColor greenColor] set];
// 3.渲染
CGContextFillPath(ctx);
// --------------------------空心圓
CGContextAddEllipseInRect(ctx, CGRectMake(70, 10, 50, 50));
[[UIColor redColor] set];
CGContextStrokePath(ctx);
// --------------------------橢圓
//畫橢圓和畫圓方法一樣,橢圓只是設(shè)置不同的長寬
CGContextAddEllipseInRect(ctx, CGRectMake(130, 10, 100, 50));
[[UIColor purpleColor] set];
CGContextFillPath(ctx);
// --------------------------直線
CGContextMoveToPoint(ctx, 20, 80); // 起點
CGContextAddLineToPoint(ctx, self.frame.size.width-10, 80); //終點
// CGContextSetRGBStrokeColor(ctx, 0, 1.0, 0, 1.0); // 顏色
[[UIColor redColor] set]; // 兩種設(shè)置顏色的方式都可以
CGContextSetLineWidth(ctx, 2.0f); // 線的寬度
CGContextSetLineCap(ctx, kCGLineCapRound); // 起點和重點圓角
CGContextSetLineJoin(ctx, kCGLineJoinRound); // 轉(zhuǎn)角圓角
CGContextStrokePath(ctx); // 渲染(直線只能繪制空心的,不能調(diào)用CGContextFillPath(ctx);)
// --------------------------三角形
CGContextMoveToPoint(ctx, 10, 150); // 第一個點
CGContextAddLineToPoint(ctx, 60, 100); // 第二個點
CGContextAddLineToPoint(ctx, 100, 150); // 第三個點
[[UIColor purpleColor] set];
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
// --------------------------矩形
CGContextAddRect(ctx, CGRectMake(20, 170, 100, 50));
[[UIColor orangeColor] set];
// CGContextStrokePath(ctx); // 空心
CGContextFillPath(ctx);
// --------------------------圓弧
CGContextAddArc(ctx, 200, 170, 50, M_PI, M_PI_4, 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
// --------------------------文字
NSString *str = @"你在紅樓,我在西游";
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSForegroundColorAttributeName] = [UIColor whiteColor]; // 文字顏色
dict[NSFontAttributeName] = [UIFont systemFontOfSize:14]; // 字體
[str drawInRect:CGRectMake(20, 250, 300, 30) withAttributes:dict];
// --------------------------圖片
UIImage *img = [UIImage imageNamed:@"yingmu"];
// [img drawAsPatternInRect:CGRectMake(20, 280, 300, 300)]; // 多個平鋪
// [img drawAtPoint:CGPointMake(20, 280)]; // 繪制到指定點,圖片有多大就顯示多大
[img drawInRect:CGRectMake(20, 280, 80, 80)]; // 拉伸
}
六、UIBezierPath
而前者所屬UIKit,其實是對Core Graphics框架關(guān)于path的進(jìn)一步封裝,所以使用起來比較簡單。但是畢竟Core Graphics更接近底層,所以它更加強大。
UIBezierPath可以創(chuàng)建基于矢量的路徑,例如橢圓或者矩形,或者有多個直線和曲線段組成的形狀。
使用UIBezierPath,你只能在當(dāng)前上下文中繪圖。
1.所以如果你當(dāng)前處于UIGraphicsBeginImageContextWithOptions函數(shù)或drawRect:方法中,你就可以直接使用UIKit提供的方法進(jìn)行繪圖。
2.如果你持有一個context:參數(shù),那么使用UIKit提供的方法之前,必須將該上下文參數(shù)轉(zhuǎn)化為當(dāng)前上下文。幸運的是,調(diào)用UIGraphicsPushContext 函數(shù)可以方便的將context:參數(shù)轉(zhuǎn)化為當(dāng)前上下文,記住最后別忘了調(diào)用UIGraphicsPopContext函數(shù)恢復(fù)上下文環(huán)境。
它的繪圖的步驟是這樣的:
- 重寫drawRect方法。但不需要我們自己獲取當(dāng)前上下文context;
- 創(chuàng)建相應(yīng)圖形的UIBezierPath對象,并設(shè)置一些修飾屬性;
- 渲染,完成繪制。
1.繪制多邊形
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor colorWithRed:0 green:0.7 blue:0 alpha:1];
//[[UIColor redColor] setFill];//設(shè)置填充色
//[[UIColor redColor] setStroke];//設(shè)置線條
[color set];//同時設(shè)置線條顏色和填充顏色
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 5.0;
aPath.lineCapStyle = kCGLineCapRound;
aPath.lineJoinStyle = kCGLineCapRound;
// 起點
[aPath moveToPoint:CGPointMake(100.0, 0.0)];
// 繪制線條
[aPath addLineToPoint:CGPointMake(200.0, 40.0)];
[aPath addLineToPoint:CGPointMake(160, 140)];
[aPath addLineToPoint:CGPointMake(40.0, 140)];
[aPath addLineToPoint:CGPointMake(0.0, 40.0)];
[aPath closePath];//第五條線通過調(diào)用closePath方法得到的
//根據(jù)坐標(biāo)點連線
[aPath stroke];
[aPath fill];
}
//橢圓
UIBezierPath* aPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, 100, 50)];
//矩形
UIBezierPath* aPath = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, 100, 50)];
2.圓弧
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor redColor];
[color set]; //設(shè)置線條顏色
UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(80, 80)
radius:75
startAngle:0
endAngle:DEGREES_TO_RADIANS(135)
clockwise:YES];
aPath.lineWidth = 5.0;
aPath.lineCapStyle = kCGLineCapRound; //線條拐角
aPath.lineJoinStyle = kCGLineCapRound; //終點處理
[aPath stroke];
}
3.曲線
兩種曲線:
-
一個control point
- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor redColor];
[color set]; //設(shè)置線條顏色
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 5.0;
aPath.lineCapStyle = kCGLineCapRound; //線條拐角
aPath.lineJoinStyle = kCGLineCapRound; //終點處理
[aPath moveToPoint:CGPointMake(20, 100)];
[aPath addQuadCurveToPoint:CGPointMake(120, 100) controlPoint:CGPointMake(70, 0)];
[aPath stroke];
}
2.兩個control point

- (void)drawRect:(CGRect)rect
{
UIColor *color = [UIColor redColor];
[color set]; //設(shè)置線條顏色
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 5.0;
aPath.lineCapStyle = kCGLineCapRound; //線條拐角
aPath.lineJoinStyle = kCGLineCapRound; //終點處理
[aPath moveToPoint:CGPointMake(5, 80)];
[aPath addCurveToPoint:CGPointMake(155, 80) controlPoint1:CGPointMake(80, 0) controlPoint2:CGPointMake(110, 100)];
[aPath stroke];
}
