Quartz 2D介紹
- 什么是Quartz2D ?
- Quartz 2D是?個二維繪圖引擎,同時支持iOS和Mac系統。
- Quartz 2D能完成的工作?
- 繪制圖形 : 線條\三角形\矩形\圓\弧形
- 繪制文字
- 繪制\生成圖片(圖像)
- 讀取\生成PDF
- 截圖\裁剪圖片
- 自定義UI控件
- 其他需要了解的內容 ?
- Quartz 2D是純C語言的
- Quartz 2D的API來自于CoreGraphics框架
- 數據類型和函數基本都是CG作為前綴
- CGContextRef
- CGPathRef
- CGContextStrokePath(ctx)
- 使用Quartz2D繪圖的基本步驟:
- 自定義view
- 重寫drawRect方法
- 1.獲取圖形上下文
- 2.創建路徑對象(添加路徑)
- 3.渲染
繪制基本圖形
- 繪制一條線段:
- 獲取圖形上下文
- 移動到起點
- 添加另一點
- 渲染
// 1.獲取圖形上下文 CGContextRef cxtRef = UIGraphicsGetCurrentContext(); // 2.添加路徑 // 起點 CGContextMoveToPoint(cxtRef, 100, 80); // 另外一個點 CGContextAddLineToPoint(cxtRef, 200, 200); // 3.渲染 CGContextStrokePath(cxtRef); // 僅僅畫線
- 線段效果圖</br>
繪制線段.png
- 繪制2條線段
// 1.獲取圖形上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
// 2.添加路徑
// 起點
CGContextMoveToPoint(cxtRef, 50, 50);
// 另外一個點
CGContextAddLineToPoint(cxtRef, 200, 100);
// 第2條線
CGContextAddLineToPoint(cxtRef, 40, 180);
// 3.渲染
CGContextStrokePath(cxtRef);
- 2條線效果圖</br>
繪制兩條線段.png
注意:CGContextStrokePath(cxtRef);只是進行畫線,CGContextFillPath(cxtRef)會將線圍起來的部分全部畫出
- 使用CGContextFillPath(cxtRef)的效果</br>
fill的效果.png
- 繪制三角形
// 1.獲取圖形上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
// 2.添加路徑
// 起點
CGContextMoveToPoint(cxtRef, 50, 50);
// 另外一個點
CGContextAddLineToPoint(cxtRef, 200, 50);
// 第2條線
CGContextAddLineToPoint(cxtRef, 125, 180);
// 再向起點連一條線
CGContextAddLineToPoint(cxtRef, 50, 50);
// 3.渲染
CGContextStrokePath(cxtRef); // 僅僅畫線
- 三角形效果圖</br>
三角形.png
繪制其他基本圖形
通過UIBezierPath繪制基本圖形
注意:如果在繪制一部分圖形后仍需要繪制圖形,必須將前面的路徑關閉,再重新開始繪制。
- 三角形及線段
// 1.獲取圖形上下文 CGContextRef cxtRef = UIGraphicsGetCurrentContext(); // 2.圖形路徑 UIBezierPath *bezierPath = [UIBezierPath bezierPath]; [bezierPath moveToPoint:CGPointMake(10, 10)]; [bezierPath addLineToPoint:CGPointMake(200, 200)]; [bezierPath addLineToPoint:CGPointMake(10, 250)]; [bezierPath addLineToPoint:CGPointMake(10, 10)]; // 2.1如果需要再繪制其他的圖形就必須先把當前的路徑關閉 [bezierPath closePath]; // 2.2.再繪制一條線段 [bezierPath moveToPoint:CGPointMake(250, 10)]; [bezierPath addLineToPoint:CGPointMake(250, 290)]; // 需要的是CGPathRef類型,可以通過.CGPath進行轉換 CGContextAddPath(cxtRef, bezierPath.CGPath); // 3.渲染 CGContextDrawPath(cxtRef, kCGPathStroke);
* 通過UIBezierPath繪制基本圖形效果圖</br>

#### 繪制矩形
```objc
// 1.獲取圖形上下文
CGContextRef ctxRef = UIGraphicsGetCurrentContext();
// 2.創建路徑對象
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 200, 100)];
// 3.將路徑對象添加到"圖形上下文"
CGContextAddPath(ctxRef, path.CGPath);
// 4.渲染
CGContextDrawPath(ctxRef, kCGPathStroke);
- 矩形效果圖</br>
繪制矩形.png
繪制圓角矩形
// 2.創建路徑對象
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 10, 200, 100) cornerRadius:50];
-
圓角矩形效果圖</br>
繪制圓角矩形.png
繪制橢圓
// 2.創建路徑對象
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 200, 100)];
- 橢圓效果圖</br>
繪制橢圓.png
繪制圓弧
- clockWise參數,代表繪制時YES:是逆時針繪制 NO:是順時針繪制
// 2.創建路徑對象
// 圓心
CGPoint center = CGPointMake(150, 150);
// 半徑
CGFloat radius = 100;
// 開始角度
CGFloat startAngle = 0;
// 結束角度
CGFloat endAngle = M_PI_2;
// 是否為順時針
BOOL clokcWise = NO;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:clokcWise];
- 圓弧效果圖</br>
繪制圓弧.png
繪制圓形
// 圓心
CGPoint center = CGPointMake(150, 150);
// 半徑
CGFloat radius = 100;
// 開始角度
CGFloat startAngle = 0;
// 結束角度
CGFloat endAngle = M_PI * 2;
// 是否為順時針
BOOL clokcWise = YES;
return [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:clokcWise];
- 圓形效果圖</br>
繪制圓形.png
繪制常見圖形
- 繪制扇形
- 繪制餅狀圖
- 繪制柱狀圖
- 繪制下載進度條
繪制扇形
- 需要繪制弧形,指定起始角度及結束角度
- 最后需要將弧形終點與圓心點連起來,再通過填充渲染就可以
// 1.獲取圖形上下文 CGContextRef cxtRef = UIGraphicsGetCurrentContext(); // 2.創建弧形的路徑對象 // 圓心 CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5); // 半徑 CGFloat radius = MIN(rect.size.width, rect.size.height) * 0.5; UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI_4 clockwise:YES]; // 必須要將終點與圓形連線 [path addLineToPoint:center]; // 4.添加到圖形上下文中 CGContextAddPath(cxtRef, path.CGPath); // 5.渲染
// CGContextDrawPath(cxtRef, kCGPathStroke);
CGContextDrawPath(cxtRef, kCGPathFill);
```
-
扇形效果圖</br>
繪制扇形.png
繪制餅狀圖
- 數組數據
- 通過計算每個元素所占的比例
- 獲取圖形上下文
- 計算好圓心及半徑
- 遍歷集合數據進行繪制
- 計算每個扇形需要旋轉的角度
- 創建路徑對象進行繪制
注意:在繪制時,每個扇形的終止角度 = 上一個扇形的結束角度 + 當前扇形所需要的角度
每次遍歷最后都需要將扇形的起始角度置為上一個扇形的結束角度
#pragma mark - 繪制餅狀圖
- (void)drawRect:(CGRect)rect {
// 1.數據
NSArray *data = @[@25, @15, @10, @5, @30, @10, @5];
// 2.遍歷數據進行求和
int total = 0;
for (NSNumber *number in data) {
float num = number.floatValue;
total += num;
}
// 3.進行繪圖操作
// 3.1獲取圖形上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
// 3.2遍歷集合進行繪圖操作
// 圓心
CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
// 半徑
CGFloat radius = MIN(rect.size.width, rect.size.height) * 0.5;
// 起始角度和結束角度
// 注意:要在block內修改外部局部變量的值是必須要加__block進行修飾的
__block CGFloat startAngle = 0;
__block CGFloat endAngle = 0;
// 遍歷集合
[data enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
// 轉為float類型
float num = obj.floatValue;
// 計算單獨一個數據結束角度,需要用它所占的角度 + 起始角度
endAngle = (num / total) * (M_PI * 2) + startAngle;
// 3.2.1創建路徑對象
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
// 3.2.2將弧線的終點與圓心連接起來
[path addLineToPoint:center];
// 3.2.3使用隨機色進行渲染
[[UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0] set];
// 3.2.4添加到圖形上下文中
CGContextAddPath(cxtRef, path.CGPath);
// 3.2.5渲染
CGContextDrawPath(cxtRef, kCGPathFill);
// 3.2.6修改起始角度
startAngle = endAngle;
}];
// 4.創建同心圓遮蓋中間部分
UIBezierPath *arcPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius - 70 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
[self.backgroundColor setFill];
CGContextAddPath(cxtRef, arcPath.CGPath);
// 渲染
CGContextDrawPath(cxtRef, kCGPathFill);
}
- 餅狀圖效果圖</br>
繪制餅狀圖.png
繪制柱狀圖
- 計算所占比例
- 獲取圖形上下文
- 計算寬度,遍歷集合進行繪制
#pragma mark - 繪制柱狀圖
- (void)drawRect:(CGRect)rect {
// 1.數據
NSArray *data = @[@100, @200, @300, @700, @79, @400];
// 2.遍歷數據進行求和
float total = 0;
for (NSNumber *number in data) {
float num = number.floatValue;
total += num;
}
// 3.進行繪圖操作
// 3.1獲取圖形上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
// 3.2遍歷集合進行繪圖操作
// 3.2.1計算寬度
CGFloat width = rect.size.width / (data.count * 2 - 1);
[data enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
// 計算高度
CGFloat height = obj.floatValue / total * rect.size.height * 2;
// 計算y
CGFloat y = rect.size.height - height;
// 計算x
CGFloat x = (2 * width) * idx;
// 創建路徑對象
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, width, height)];
// 添加到圖形上下文中
CGContextAddPath(cxtRef, path.CGPath);
// 設置隨機色
[[UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0] set];
// 渲染
CGContextDrawPath(cxtRef, kCGPathFill);
}];
}
- 柱狀圖效果圖</br>
繪制柱形圖.png
繪制下載進度條
- 監聽slider的滑動事件
- 將slider的值傳遞給自定義view
- 在自定義view中重寫set方法,進行繪制
- 繪制時弧線的結束角度根據傳入的進度值進行計算
#pragma mark - 繪制下載進度條
- (void)drawRect:(CGRect)rect {
// 1.獲取上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
// 2.創建路徑對象
// 圓心
CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
// 半徑
CGFloat radius = MIN(rect.size.width, rect.size.height) * 0.5;
// 起點
CGFloat startAngle = -M_PI_2;
CGFloat endAngle = self.progress * M_PI * 2 - M_PI_2;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
[path addLineToPoint:center];
#pragma mark - 創建一個圓形,利用奇偶填充模式留出中間的空白處
// UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:radius - 50 startAngle:startAngle endAngle:endAngle clockwise:YES];
// [path2 addLineToPoint:center];
// 3.添加到上下文中
CGContextAddPath(cxtRef, path.CGPath);
// CGContextAddPath(cxtRef, path2.CGPath);
// 設置顏色
[[UIColor brownColor] set];
// 4.渲染
CGContextDrawPath(cxtRef, kCGPathFill);
// CGContextDrawPath(cxtRef, kCGPathEOFill);
}
- 下載進度條圖效果圖</br>
繪制下載進度條.gif
圖形上下文的矩陣操作
注意: 紅色框為上下文的邊界
旋轉
#pragma mark - 旋轉 CTM
// 注意:是繞著左上角進行轉動
CGContextRotateCTM(cxtRef, M_PI_4);
- 旋轉上下文</br>
旋轉.png
縮放
#pragma mark - 縮放 CTM
// 注意:是以左上角為圓點縮放
CGContextScaleCTM(cxtRef, 0.5, 0.5);
- 縮小上下文</br>
縮放.png
平移
#pragma mark - 平移
CGContextTranslateCTM(cxtRef, 200, -100);
- 平移上下文</br>
平移.png
- 旋轉縮放平移</br>
旋轉縮放平移.png
圖形上下文棧介紹
- 在對圖形上下文進行矩陣操作之前先將圖像上下文最初的狀態保存起來。保存的位置就是圖形上下文的棧。
- 在需要原始狀態的時候進行再回復原始的狀態的。
#pragma mark - 矩陣操作
- (void)drawRect:(CGRect)rect {
//獲取圖形上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
//MARK: - 在矩陣操作前保存圖形上下文
CGContextSaveGState(cxtRef);
#pragma mark - 旋轉 CTM
// 注意:是繞著左上角進行轉動
CGContextRotateCTM(cxtRef, M_PI_4);
#pragma mark - 縮放 CTM
// 注意:是以左上角為圓點縮放
CGContextScaleCTM(cxtRef, 0.5, 0.5);
#pragma mark - 平移
CGContextTranslateCTM(cxtRef, 200, -100); //為什么y值為0 和y值為-100 x值也會改變 縮放同時改變位置 位置會不準
//創建路徑
//圓形
UIBezierPath *roundPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(180, 150) radius:100 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
//矩形
UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:CGRectMake(150, 280, 200, 100)];
//直線
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(50, 50)];
[linePath addLineToPoint:CGPointMake(350, 400)];
//添加路徑
CGContextAddPath(cxtRef, roundPath.CGPath);
CGContextAddPath(cxtRef, rectPath.CGPath);
CGContextAddPath(cxtRef, linePath.CGPath);
//渲染
CGContextDrawPath(cxtRef, kCGPathStroke);
//MARK: - 在執行完畢矩陣操作以后,恢復上下文
CGContextRestoreGState(cxtRef);
//繪制與控制器視圖大小相等的方框方便觀察
UIBezierPath *rectP = [UIBezierPath bezierPathWithRect:rect] ;
//設置矩形的顏色
[[UIColor redColor] setStroke];
//設置矩形的線寬
rectP.lineWidth = 10;
[rectP stroke];
}
圖形上下文的內存管理
- CoreGraphics框架里面的使用到"create"和"copy","retain"函數創建的對象,最后都需要進行釋放
// 1.獲取上下文
CGContextRef cxtRef = UIGraphicsGetCurrentContext();
// 2.創建路徑對象
CGMutablePathRef path = CGPathCreateMutable();
// 起點
CGPathMoveToPoint(path, NULL, 50, 50);
// 另一點
CGPathAddLineToPoint(path, NULL, 100, 100);
// 3.將路徑對象添加到圖形上下文中
CGContextAddPath(cxtRef, path);
// 4.渲染
CGContextDrawPath(cxtRef, kCGPathStroke);
// 5.釋放
// CGPathRelease(path);
#pragma mark - CoreGraphics框架里面的使用到"create"和"copy","retain"函數創建的對象,最后都需要進行釋放
CFRelease(path);
繪制圖片和文字
繪制圖片
//1.加載圖片
UIImage *mjImage = [UIImage imageNamed:@"頭像"];
//2.1方式1 通過一個點開始繪制
[mjImage drawAtPoint:CGPointMake(50, 50)];
通過一個點開始繪制.png
//2.2方式2 通過某個區域繪制,可能會壓縮或者拉伸圖片,使圖片不夠美觀
[mjImage drawInRect:CGRectMake(50, 50, 100, 150)];
通過某個區域繪制.png
//2.3方式3 在某個區域內以平鋪的方式繪制圖片
[mjImage drawAsPatternInRect:CGRectMake(0, 0, 300, 300)];
在某個區域內以平鋪的方式繪制圖片.png
繪制文字
//字符串
NSString *str = [NSString stringWithFormat:@"說好的不熬夜呢?"];
NSDictionary *dic = @{
NSFontAttributeName : [UIFont systemFontOfSize:20],
NSForegroundColorAttributeName : [UIColor redColor]
};
//方式1. 從某一個點開始繪制
[str drawAtPoint:CGPointMake(50, 50) withAttributes:dic];
從某一個點開始繪制.png
//方式2. 在某一個區域進行繪制 (會自動換行,但是區域不要小于字體所占面積大小)
[str drawInRect:CGRectMake(150, 150, 80, 150) withAttributes:dic];
在某一個區域進行繪制.png