什么是Quartz2D
- Quartz2D是?個(gè)二維繪圖引擎,同時(shí)支持iOS和Mac系統(tǒng)
Quartz2D的API是純C語?言的Quartz2D的API來自于Core Graphics框架
Quartz2D的數(shù)據(jù)類型和函數(shù)基本都以CG作為前綴期奔,例如下面2個(gè)類型:
1.CGContextRef
2.CGPathRef
Quartz2D的path
Points
void CGContextMoveToPoint (
CGContextRef c,
CGFloat x,
CGFloat y
);
指定一個(gè)點(diǎn)成為current point
Quartz會(huì)跟蹤current point一般執(zhí)行完一個(gè)相關(guān)函數(shù)后,current point都會(huì)相應(yīng)的改變.
Lines
相關(guān)的幾個(gè)函數(shù)
void CGContextAddLineToPoint (
CGContextRef c,
CGFloat x,
CGFloat y
);
創(chuàng)建一條直線卦睹,從current point到 (x,y)
然后current point會(huì)變成(x,y)
void CGContextAddLines (
CGContextRef c,
const CGPoint points[],
size_t count
);
創(chuàng)建多條直線谎势,比如points有兩個(gè)點(diǎn)占遥,那么會(huì)畫兩條直線 從current point到 (x1,y1),
然后是(x1,y1)到(x2,y2)
然后current point會(huì)變成points中的最后一個(gè)點(diǎn)
Arcs
兩種方法創(chuàng)建弧度
- 第一種
void CGContextAddArc (
CGContextRef c,
CGFloat x, //圓心的x坐標(biāo)
CGFloat y, //圓心的x坐標(biāo)
CGFloat radius, //圓的半徑
CGFloat startAngle, //開始弧度
CGFloat endAngle, //結(jié)束弧度
int clockwise //0表示順時(shí)針,1表示逆時(shí)針
);
假如想創(chuàng)建一個(gè)完整的圓圈私股,那么 開始弧度就是0 結(jié)束弧度是 2pi议街, 因?yàn)閳A周長(zhǎng)是 2pir.
最后割捅,函數(shù)執(zhí)行完后奶躯,current point就被重置為(x,y).
還有一點(diǎn)要注意的是,假如當(dāng)前path已經(jīng)存在一個(gè)subpath亿驾,那么這個(gè)函數(shù)執(zhí)行的另外一個(gè)效果是
會(huì)有一條直線嘹黔,從current point到弧的起點(diǎn)
- 第二種
void CGContextAddArcToPoint (
CGContextRef c,
CGFloat x1, //端點(diǎn)1的x坐標(biāo)
CGFloat y1, //端點(diǎn)1的y坐標(biāo)
CGFloat x2, //端點(diǎn)2的x坐標(biāo)
CGFloat y2, //端點(diǎn)2的y坐標(biāo)
CGFloat radius //半徑
);
原理:首先畫兩條線,這兩條線分別是 current point to (x1,y1) 和(x1,y1) to (x2,y2).
這樣就是出現(xiàn)一個(gè)以(x1,y1)為頂點(diǎn)的兩條射線莫瞬,
然后定義半徑長(zhǎng)度儡蔓,這個(gè)半徑是垂直于兩條射線的,這樣就能決定一個(gè)圓了乏悄,更好的理解看下圖浙值,不過個(gè)人認(rèn)為下圖所標(biāo)的 tangent point 1的位置是錯(cuò)誤的。
最后檩小,函數(shù)執(zhí)行完后开呐,current point就被重置為(x2,y2).
還有一點(diǎn)要注意的是,假如當(dāng)前path已經(jīng)存在一個(gè)subpath规求,那么這個(gè)函數(shù)執(zhí)行的另外一個(gè)效果是
會(huì)有一條直線筐付,從current point到(x1,y1)
Curves
畫曲線,一般是一條直線阻肿,然后定義幾個(gè)控制點(diǎn)瓦戚,使直線變彎曲。
- 三次曲線函數(shù)
void CGContextAddCurveToPoint (
CGContextRef c,
CGFloat cp1x, //控制點(diǎn)1 x坐標(biāo)
CGFloat cp1y, //控制點(diǎn)1 y坐標(biāo)
CGFloat cp2x, //控制點(diǎn)2 x坐標(biāo)
CGFloat cp2y, //控制點(diǎn)2 y坐標(biāo)
CGFloat x, //直線的終點(diǎn) x坐標(biāo)
CGFloat y //直線的終點(diǎn) y坐標(biāo)
);
假如第二個(gè)控制點(diǎn)(cp2x丛塌,cp2y)比(cp1x,cp1y) 更接近c(diǎn)urrent point较解,那么會(huì)形成一個(gè)封閉的曲線
- 二次曲線函數(shù)
void CGContextAddQuadCurveToPoint (
CGContextRef c,
CGFloat cpx, //控制點(diǎn) x坐標(biāo)
CGFloat cpy, //控制點(diǎn) y坐標(biāo)
CGFloat x, //直線的終點(diǎn) x坐標(biāo)
CGFloat y //直線的終點(diǎn) y坐標(biāo)
);
執(zhí)行完函數(shù)貌似current point不會(huì)變化,沒有具體測(cè)試過
Ellipses橢圓
void CGContextAddEllipseInRect (
CGContextRef context,
CGRect rect //一矩形
);
如果矩形是一個(gè)正方形赴邻,那么畫出來就是一個(gè)圓
Rectangles矩形
void CGContextAddRect (
CGContextRef c,
CGRect rect
);
Quartz2D畫圖練習(xí)
- 畫線
- (void)drawRect:(CGRect)rect
{
// 1.獲得圖形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.拼接圖形(路徑)
// 設(shè)置線段寬度
CGContextSetLineWidth(ctx, 10);
// 設(shè)置線段頭尾部的樣式
CGContextSetLineCap(ctx, kCGLineCapRound);
// 設(shè)置線段轉(zhuǎn)折點(diǎn)的樣式
CGContextSetLineJoin(ctx, kCGLineJoinRound);
/** 第1根線段 **/
// 設(shè)置顏色
CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);
// 設(shè)置一個(gè)起點(diǎn)
CGContextMoveToPoint(ctx, 10, 10);
// 添加一條線段到(100, 100)
CGContextAddLineToPoint(ctx, 100, 100);
// 渲染一次
CGContextStrokePath(ctx);
/** 第2根線段 **/
// 設(shè)置顏色
CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);
// 設(shè)置一個(gè)起點(diǎn)
CGContextMoveToPoint(ctx, 200, 190);
// 添加一條線段到(150, 40)
CGContextAddLineToPoint(ctx, 150, 40);
CGContextAddLineToPoint(ctx, 120, 60);
// 3.渲染顯示到view上面
CGContextStrokePath(ctx);
}
- 矩形
// 1.獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.畫矩形
CGContextAddRect(ctx, CGRectMake(10, 10, 150, 50));
// set : 同時(shí)設(shè)置為實(shí)心和空心顏色
// setStroke : 設(shè)置空心顏色
// setFill : 設(shè)置實(shí)心顏色
[[UIColor greenColor] set];
// CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
// 3.繪制圖形
CGContextFillPath(ctx);
- 三角形
// 1.獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.畫三角形
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 150, 80);
// 關(guān)閉路徑(連接起點(diǎn)和最后一個(gè)點(diǎn))
CGContextClosePath(ctx);
//
CGContextSetRGBStrokeColor(ctx, 0, 1, 0, 1);
// 3.繪制圖形
CGContextStrokePath(ctx);
- 畫圓
// 1.獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.畫1/4圓
CGContextMoveToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 100, 150);
CGContextAddArc(ctx, 100, 100, 50, -M_PI_2, M_PI, 1);
CGContextClosePath(ctx);
[[UIColor redColor] set];
// 3.顯示所繪制的東西
CGContextFillPath(ctx);
- 圓弧
// 1.獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.畫圓弧
// x\y : 圓心
// radius : 半徑
// startAngle : 開始角度
// endAngle : 結(jié)束角度
// clockwise : 圓弧的伸展方向(0:順時(shí)針, 1:逆時(shí)針)
CGContextAddArc(ctx, 100, 10, 50, M_PI_2, M_PI, 0);
[[UIColor redColor] set];
// 3.顯示所繪制的東西
CGContextFillPath(ctx);
- 圓
// 1.獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.畫圓
CGContextAddEllipseInRect(ctx, CGRectMake(50, 10, 100, 100));
CGContextSetLineWidth(ctx, 10);
[[UIColor greenColor] set];
// 3.顯示所繪制的東西
CGContextStrokePath(ctx);
- 畫文字和圖片
// 1.取得圖片
UIImage *image = [UIImage imageNamed:@"me"];
// 2.畫
// [image drawAtPoint:CGPointMake(50, 50)];
// [image drawInRect:CGRectMake(0, 0, 150, 150)];
[image drawAsPatternInRect:CGRectMake(0, 0, 200, 200)];
// 3.畫文字
NSString *str = @"為xxx所畫";
[str drawInRect:CGRectMake(0, 0, 100, 30) withAttributes:nil];
- 畫文字
// 1.獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.畫矩形
CGRect cubeRect = CGRectMake(50, 50, 100, 100);
CGContextAddRect(ctx, cubeRect);
// 3.顯示所繪制的東西
CGContextFillPath(ctx);
// 4.畫文字
NSString *str = @"你好";
// [str drawAtPoint:CGPointZero withAttributes:nil];
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
// NSForegroundColorAttributeName : 文字顏色
// NSFontAttributeName : 字體
attrs[NSForegroundColorAttributeName] = [UIColor redColor];
attrs[NSFontAttributeName] = [UIFont systemFontOfSize:50];
[str drawInRect:cubeRect withAttributes:attrs];
- 圖形上下文棧
// 1.獲得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 將ctx拷貝一份放到棧中
CGContextSaveGState(ctx);
// 設(shè)置繪圖狀態(tài)
CGContextSetLineWidth(ctx, 10);
[[UIColor redColor] set];
CGContextSetLineCap(ctx, kCGLineCapRound);
// 第1根線
CGContextMoveToPoint(ctx, 50, 50);
CGContextAddLineToPoint(ctx, 120, 190);
CGContextStrokePath(ctx);
// 將棧頂?shù)纳舷挛某鰲?替換當(dāng)前的上下文
CGContextRestoreGState(ctx);
// 第2根線
CGContextMoveToPoint(ctx, 10, 70);
CGContextAddLineToPoint(ctx, 220, 290);
CGContextStrokePath(ctx);
// CGContextDrawPath(ctx, kCGPathStroke);
- 矩陣操作
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextRotateCTM(ctx, M_PI_4 * 0.3);
CGContextScaleCTM(ctx, 0.5, 0.5);
CGContextTranslateCTM(ctx, 0, 150);
CGContextAddRect(ctx, CGRectMake(10, 10, 50, 50));
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx);
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
CGContextMoveToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 200, 250);
CGContextStrokePath(ctx);
- 裁剪
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
// 0.畫圓
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
[[UIColor redColor] set];
// 裁剪
CGContextClip(ctx);
CGContextFillPath(ctx);
// 1.顯示圖片
UIImage *image = [UIImage imageNamed:@"1"];
[image drawAtPoint:CGPointMake(100, 100)];
CGContextRestoreGState(ctx);
CGContextAddRect(ctx, CGRectMake(0, 0, 50, 50));
[[UIColor yellowColor] set];
CGContextFillPath(ctx);
提示:- (void)drawRect:(CGRect)rect默認(rèn)只會(huì)在view第一次顯示的時(shí)候調(diào)用(只能由系統(tǒng)自動(dòng)調(diào)用, 不能手動(dòng)調(diào)用)印衔,如果要重新繪制調(diào)用 setNeedsDisplay方法。
定時(shí)器快速調(diào)用setNeedsDisplay姥敛,如果是一秒調(diào)用一次可以用NSTimer奸焙,如果0.1秒調(diào)用一次,要用CADisplayLink。每秒刷新60次与帆。
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- CGMutablePathRef 的使用了赌。
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 1.先創(chuàng)建一個(gè)路徑
CGMutablePathRef linePath = CGPathCreateMutable();
// 2.拼接路徑
CGPathMoveToPoint(linePath, NULL, 0, 0);
CGPathAddLineToPoint(linePath, NULL, 100, 100);
// 3.添加路徑到上下文
CGContextAddPath(ctx, linePath);
CGMutablePathRef circlePath = CGPathCreateMutable();
CGPathAddArc(circlePath, NULL, 150, 150, 50, 0, M_PI * 2, 0);
CGContextAddPath(ctx, circlePath);
// 4.渲染
CGContextStrokePath(ctx);
CGPathRelease(linePath);
CGPathRelease(circlePath);
- 水印
+ (instancetype)waterImageWithBg:(NSString *)bg logo:(NSString *)logo
{
UIImage *bgImage = [UIImage imageNamed:bg];
// 上小文 : 基于位圖(bitmap) , 所有的東西需要繪制到一張新的圖片上去
// 1.創(chuàng)建一個(gè)基于位圖的上下文(開啟一個(gè)基于位圖的上下文)
// size : 新圖片的尺寸
// opaque : YES : 不透明, NO : 透明
// 這行代碼過后.就相當(dāng)于常見一張新的bitmap,也就是新的UIImage對(duì)象
// 1.創(chuàng)建一個(gè)基于位圖的上下文(開啟一個(gè)基于位圖的上下文)
UIGraphicsBeginImageContextWithOptions(bgImage.size, NO, 0.0);
// 2.畫背景
[bgImage drawInRect:CGRectMake(0, 0, bgImage.size.width, bgImage.size.height)];
// 3.畫右下角的水印
UIImage *waterImage = [UIImage imageNamed:logo];
CGFloat scale = 0.2;
CGFloat margin = 5;
CGFloat waterW = waterImage.size.width * scale;
CGFloat waterH = waterImage.size.height * scale;
CGFloat waterX = bgImage.size.width - waterW - margin;
CGFloat waterY = bgImage.size.height - waterH - margin;
[waterImage drawInRect:CGRectMake(waterX, waterY, waterW, waterH)];
// 4.從上下文中取得制作完畢的UIImage對(duì)象
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 5.結(jié)束上下文
UIGraphicsEndImageContext();
return newImage;
}
- 圖片裁剪
+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor
{
// 1.加載原圖
UIImage *oldImage = [UIImage imageNamed:name];
// 2.開啟上下文
CGFloat imageW = oldImage.size.width + 2 * borderWidth;
CGFloat imageH = oldImage.size.height + 2 * borderWidth;
CGSize imageSize = CGSizeMake(imageW, imageH);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
// 3.取得當(dāng)前的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 4.畫邊框(大圓)
[borderColor set];
CGFloat bigRadius = imageW * 0.5; // 大圓半徑
CGFloat centerX = bigRadius; // 圓心
CGFloat centerY = bigRadius;
CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
CGContextFillPath(ctx); // 畫圓
// 5.小圓
CGFloat smallRadius = bigRadius - borderWidth;
CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
// 裁剪(后面畫的東西才會(huì)受裁剪的影響)
CGContextClip(ctx);
// 6.畫圖
[oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];
// 7.取圖
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 8.結(jié)束上下文
UIGraphicsEndImageContext();
return newImage;
}
- 屏幕截圖
+ (instancetype)captureWithView:(UIView *)view
{
// 1.開啟上下文
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0);
// 2.將控制器view的layer渲染到上下文
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
// 3.取出圖片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 4.結(jié)束上下文
UIGraphicsEndImageContext();
return newImage;
}
- 條紋背景
// 1.創(chuàng)建一行背景圖片
CGFloat rowW = self.view.frame.size.width;
// CGFloat rowH = 40;
CGFloat rowH = 30;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(rowW, rowH), NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 畫矩形框
[[UIColor redColor] set];
CGContextAddRect(ctx, CGRectMake(0, 0, rowW, rowH));
CGContextFillPath(ctx);
// 2.畫線
[[UIColor greenColor] set];
CGFloat lineWidth = 2;
CGContextSetLineWidth(ctx, lineWidth);
CGFloat dividerX = 0;
CGFloat dividerY = rowH - lineWidth;
CGContextMoveToPoint(ctx, dividerX, dividerY);
CGContextAddLineToPoint(ctx, rowW - dividerX, dividerY);
CGContextStrokePath(ctx);
// 3.取圖
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 4.結(jié)束上下文
UIGraphicsEndImageContext();
// 5.設(shè)置為背景
self.textView.backgroundColor = [UIColor colorWithPatternImage:newImage];