相關(guān)資源
chess.gif
gestureLock.gif
Quartz2D
Quartz2D是一個(gè)二維繪圖引擎削锰,同時(shí)支持iOS和Mac系統(tǒng)。iOS中仲闽,大部分控件都是Quartz2D繪制出來的空繁。這里需要重點(diǎn)說明一下味悄,Quartz2D的接口(函數(shù))和使用對(duì)象(或者結(jié)構(gòu)體)定義在CoreGraphics框架和UIKit中荷憋。一般情況下我們使用UIKit下面提供的對(duì)象和接口就可以實(shí)現(xiàn)豐富的功能罐脊。復(fù)雜的情況下需要混合使用,或者只使用CoreGraphics框架枯怖。CoreGraphics是C語言框架注整,使用起來不如面向?qū)ο蠓奖恪?/p>
圖形上下文
提到繪圖,我們就得了解最基本的概念度硝。圖形上下文所表示的是圖形繪制的平臺(tái)设捐。包含繪制參數(shù)以及需要執(zhí)行一系列繪圖命令的設(shè)備信息。圖形上下文定義了包括繪制顏色塘淑、裁剪區(qū)域、曲線寬度以及繪制模式信息蚂斤、文本字體信息存捺、一些合成選項(xiàng)或者是一些其他的有關(guān)繪制的基本屬性。看下圖捌治,了解一下上下文的分類:
CGContext.png這里主要分析和用到了兩種上下文:
1. Bitmap Graphics Context
位圖上下文岗钩,在這個(gè)上下文上繪制或者渲染的內(nèi)容,可以獲取成圖片(需要主動(dòng)開啟一個(gè)上下文來使用肖油,使用完畢兼吓,一定要銷毀或者關(guān)閉;所以這里也不需要在UIView 的 drawRect:方法里獲取上下文了)森枪。
開啟和關(guān)閉上下文
// 開啟一個(gè)圖片(位圖)上下文//size:上下文尺寸视搏,opaque:不透明度,scale:如果設(shè)置為0.0县袱,這個(gè)設(shè)置是屏幕的scale浑娜,例如iPhone6是2,iPhone6P是3式散。
UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);
// 關(guān)閉位圖上下文
UIGraphicsEndImageContext();
簡單示例
-
打水印
UIImage *image = [UIImage imageNamed:@"卡哇伊"]; UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0); //把圖片給繪制圖片上下文. [image drawAtPoint:CGPointZero]; //繪制文字 NSString *str = @"I Love You"; [str drawAtPoint:CGPointZero withAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:20]}]; //生成圖片 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); //手動(dòng)關(guān)閉上下文 UIGraphicsEndImageContext(); self.imageV.image = newImage;
printCharacters.png
- 擦圖
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.imageV.userInteractionEnabled = YES;
//添加手勢(shì)
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self.imageV addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)pan{
//獲取當(dāng)前手指所在的點(diǎn)
CGPoint curP = [pan locationInView:self.imageV];
CGFloat rectWH = 50;
CGFloat x = curP.x - rectWH * 0.5;
CGFloat y = curP.y - rectWH * 0.5;
CGRect rect = CGRectMake(x, y, rectWH, rectWH);
//開啟一個(gè)圖片上下文.
UIGraphicsBeginImageContextWithOptions(self.imageV.bounds.size, NO, 0);
//獲取當(dāng)前的上下文.
CGContextRef ctx = UIGraphicsGetCurrentContext();
//把UImageViwe上面的圖片給繪制到上下文.
[self.imageV.layer renderInContext:ctx];
//確定擦除區(qū)域
CGContextClearRect(ctx, rect);
//生成一張新圖片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//把上下文給關(guān)閉
UIGraphicsEndImageContext();
//給原來圖片重新賦值
self.imageV.image = newImage;
}
erasePicture.gif
- 截屏
//1.開啟圖片上下文.
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
//獲取當(dāng)前的上下文.
CGContextRef ctx = UIGraphicsGetCurrentContext();
//UIView之所能夠顯示,是因?yàn)閘ayer.把層渲染給位圖上下文.
[self.view.layer renderInContext:ctx];
//生成一張圖片.
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//如何把圖片轉(zhuǎn)換成二進(jìn)流.
NSData *data = UIImagePNGRepresentation(newImage);
[data writeToFile:@"/Users/Boat/Desktop/newImage.png" atomically:YES];
//關(guān)閉上下文.
UIGraphicsEndImageContext();
2. Layer Graphics Context
圖層上下文筋遭,針對(duì)UI控件的上下文。我們已經(jīng)很清楚暴拄,view之所以能顯示內(nèi)容漓滔,全靠layer(圖層)。
UIView 的 drawRect:方法
drawRect: 這個(gè)是UIKit提供給UIView的方法乖篷,只有在此方法中我們才可以獲取到與此View對(duì)象對(duì)應(yīng)的圖層上下文(CGContextRef)响驴;但是有時(shí)候我們?cè)谙耄O果為什么不直接給CALayer提供此方法呢那伐?可能是我才疏學(xué)淺踏施,畢竟QuartsCore也給我們提供了各種類型的layer,也許我們需要挖掘一下QuartsCore下面的CALayer罕邀。詳情請(qǐng)參考頂部的相關(guān)資源畅形。
基本繪圖
先通過基本繪圖,我們可以總結(jié)用法以及原理诉探。
- 簡單直線
// Drawing code
NSLog(@"%s",__func__);
NSLog(@"%@",NSStringFromCGRect(self.bounds));
//1.取得一個(gè)跟View相關(guān)聯(lián)的上下文.
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路徑
UIBezierPath *path = [UIBezierPath bezierPath];
//2.1.設(shè)置起點(diǎn)
[path moveToPoint:CGPointMake(10, 100)];
//2.1.添加一根線到某個(gè)點(diǎn)
[path addLineToPoint:CGPointMake(200, 20)];
//一個(gè)路徑上面可以畫多條線
[path moveToPoint:CGPointMake(10, 150)];
[path addLineToPoint:CGPointMake(200, 100)];
//把上一條線的終點(diǎn)當(dāng)作是下一條線的起點(diǎn).
[path addLineToPoint:CGPointMake(150, 200)];
//設(shè)置上下文的狀態(tài)
//設(shè)置線的寬度
CGContextSetLineWidth(ctx, 10);
//設(shè)置線的連接樣式
CGContextSetLineJoin(ctx, kCGLineJoinBevel);
//設(shè)置頂角的樣式
CGContextSetLineCap(ctx, kCGLineCapRound);
//設(shè)置線的顏色
[[UIColor greenColor] setStroke];
//3.把路徑添加到上下文
CGContextAddPath(ctx, path.CGPath);
//4.把上下文的內(nèi)容顯示View fill stroke
CGContextStrokePath(ctx);
drawLine.png
- 簡單曲線
//1.獲取跟View相關(guān)聯(lián)的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路徑
UIBezierPath *path = [UIBezierPath bezierPath];
//2.1設(shè)置起點(diǎn)
[path moveToPoint:CGPointMake(20, 200)];
//2.2添加一條曲線到某個(gè)點(diǎn).
[path addQuadCurveToPoint:CGPointMake(200, 200) controlPoint:CGPointMake(100, 10)];
CGContextSetLineWidth(ctx, 10);
//3.把路徑添加到上下文
CGContextAddPath(ctx, path.CGPath);
//4.把上下文的內(nèi)容顯示出來.
CGContextStrokePath(ctx);
drawQuadCurve.png
- 簡單矩形
//1.獲取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2.描述路徑
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 100, 100)];
//3.把路徑添加到上下文
CGContextAddPath(ctx, path.CGPath);
[[UIColor yellowColor] set];
//4.把上下文的內(nèi)容顯示
CGContextFillPath(ctx);
drawRectangle.png
-
簡單餅圖
NSArray *dataArray = @[@25,@25,@25,@25];
//畫餅圖扇形
CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
CGFloat radius = rect.size.width * 0.5 - 10;
CGFloat startA = 0;
CGFloat angle = 0;
CGFloat endA = 0;
for (NSNumber *num in dataArray) {
startA = endA;
angle = num.intValue / 100.0 * M_PI * 2;
endA = startA + angle;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
[path addLineToPoint:center];
[[self randomColor] set];
[path fill];
}
//隨機(jī)生成一個(gè)顏色
-
(UIColor *)randomColor{
CGFloat r = arc4random_uniform(256) / 255.0;
CGFloat g = arc4random_uniform(256) / 255.0;
CGFloat b = arc4random_uniform(256) / 255.0;//0-255.
// colorWithRed 0-1
return [UIColor colorWithRed:r green:g blue:b alpha:1];
}
> 
> 現(xiàn)在基本可以總結(jié)使用方法:
>
> 1. 獲得上下文
>
> 2. 繪制/拼接繪圖路徑
>
> 3. 上下文當(dāng)前棧設(shè)置日熬,包括顏色,線條等
>
> 4. 將路徑添加到上下文
>
> 5. 渲染上下文
>
> Note:
>
> 這里使用的是UIKit下面的貝塞爾曲線類肾胯,沒用使用CoreGraphics的路徑竖席。
>
> UIBezierPath包含很多對(duì)CoreGraphics的路徑(Path)的封裝,而且還提供直接渲染功能敬肚,當(dāng)然還包括對(duì)圖形上下文棧(CGContextRestoreGState)的封裝毕荐。
>
> 對(duì)于圖形上下文棧(CGContextRestoreGState)這里不做說明,請(qǐng)去站內(nèi)搜索艳馒。
#### UIKit對(duì)象直接繪圖
> 注意憎亚,這里介紹的仍然是圖層上下文(Layer Graphics Context)员寇。這里相關(guān)知識(shí)不再介紹,也不再配圖第美。有興趣可以試一試蝶锋。
1. 圖片UIImage對(duì)象相關(guān)
-
(void)drawRect:(CGRect)rect {
// Drawing code//1.加載圖片
UIImage *image = [UIImage imageNamed:@"001"];//2.繪制出來的圖片,是保持原來圖片
// [image drawAtPoint:CGPointZero];
//2. 把圖片填充到這個(gè)rect當(dāng)中.
[image drawInRect:rect];
// 添加裁剪區(qū)域 .把超區(qū)裁剪區(qū)域以外都裁剪掉
UIRectClip(CGRectMake(0, 0, 50, 50));
// [image drawAsPatternInRect:self.bounds];
}
2. 文字NSSting相關(guān)
NSString *str = @"辛為舟帥氣側(cè)漏";
//AtPoint:文字所畫的位置
//withAttributes:描述文字的屬性.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//設(shè)置文字大小
dict[NSFontAttributeName] = [UIFont systemFontOfSize:50];
//設(shè)置文字顏色
dict[NSForegroundColorAttributeName] = [UIColor greenColor];
//設(shè)置描邊寬度
dict[NSStrokeWidthAttributeName] = @2;
//設(shè)置描邊顏色
dict[NSStrokeColorAttributeName] = [UIColor blueColor];
//設(shè)置陰影
NSShadow *shadow = [[NSShadow alloc] init];
//設(shè)置陰影的便宜量
shadow.shadowOffset = CGSizeMake(10, 10);
//設(shè)置陰影顏色
shadow.shadowColor = [UIColor greenColor];
//設(shè)置陰影模糊程序
shadow.shadowBlurRadius = 1;
dict[NSShadowAttributeName] = shadow;
//不會(huì)自動(dòng)換行
[str drawAtPoint:CGPointZero withAttributes:dict];
//會(huì)自動(dòng)換行.
[str drawInRect:self.bounds withAttributes:dict];