iOS之Quartz2D
什麼是Quartz2D
- Quartz2D是⼀個二維繪圖引擎,同時支援iOS和Mac系統
Quartz2D的API是純C語⾔言的Quartz2D的API來自於Core Graphics框架
Quartz2D的資料型別和函式基本都以CG作為字首,例如下面2個型別:
1.CGContextRef
2.CGPathRef
Quartz2D的path
Points
void CGContextMoveToPoint (
CGContextRef c,
CGFloat x,
CGFloat y
);
指定一個點成為current point
Quartz會跟蹤current point一般執行完一個相關函式後,current point都會相應的改變.
Lines
相關的幾個函式
void CGContextAddLineToPoint (
CGContextRef c,
CGFloat x,
CGFloat y
);
建立一條直線,從current point到 (x,y)
然後current point會變成(x,y)
void CGContextAddLines (
CGContextRef c,
const CGPoint points[],
size_t count
);
建立多條直線,比如points有兩個點,那麼會畫兩條直線 從current point到 (x1,y1),
然後是(x1,y1)到(x2,y2)
然後current point會變成points中的最後一個點
Arcs
兩種方法建立弧度
- 第一種
void CGContextAddArc (
CGContextRef c,
CGFloat x, //圓心的x座標
CGFloat y, //圓心的x座標
CGFloat radius, //圓的半徑
CGFloat startAngle, //開始弧度
CGFloat endAngle, //結束弧度
int clockwise //0表示順時針,1表示逆時針
);
假如想建立一個完整的圓圈,那麼 開始弧度就是0 結束弧度是 2pi, 因為圓周長是 2pir.
最後,函式執行完後,current point就被重置為(x,y).
還有一點要注意的是,假如當前path已經存在一個subpath,那麼這個函式執行的另外一個效果是
會有一條直線,從current point到弧的起點
- 第二種
void CGContextAddArcToPoint (
CGContextRef c,
CGFloat x1, //端點1的x座標
CGFloat y1, //端點1的y座標
CGFloat x2, //端點2的x座標
CGFloat y2, //端點2的y座標
CGFloat radius //半徑
);
原理:首先畫兩條線,這兩條線分別是 current point to (x1,y1) 和(x1,y1) to (x2,y2).
這樣就是出現一個以(x1,y1)為頂點的兩條射線,
然後定義半徑長度,這個半徑是垂直於兩條射線的,這樣就能決定一個圓了,更好的理解看下圖,不過個人認為下圖所標的 tangent point 1的位置是錯誤的。
最後,函式執行完後,current point就被重置為(x2,y2).
還有一點要注意的是,假如當前path已經存在一個subpath,那麼這個函式執行的另外一個效果是
會有一條直線,從current point到(x1,y1)
Curves
畫曲線,一般是一條直線,然後定義幾個控制點,使直線變彎曲。
- 三次曲線函式
void CGContextAddCurveToPoint (
CGContextRef c,
CGFloat cp1x, //控制點1 x座標
CGFloat cp1y, //控制點1 y座標
CGFloat cp2x, //控制點2 x座標
CGFloat cp2y, //控制點2 y座標
CGFloat x, //直線的終點 x座標
CGFloat y //直線的終點 y座標
);
假如第二個控制點(cp2x,cp2y)比(cp1x,cp1y) 更接近current point,那麼會形成一個封閉的曲線
- 二次曲線函式
void CGContextAddQuadCurveToPoint (
CGContextRef c,
CGFloat cpx, //控制點 x座標
CGFloat cpy, //控制點 y座標
CGFloat x, //直線的終點 x座標
CGFloat y //直線的終點 y座標
);
執行完函式貌似current point不會變化,沒有具體測試過
Ellipses橢圓
void CGContextAddEllipseInRect (
CGContextRef context,
CGRect rect //一矩形
);
如果矩形是一個正方形,那麼畫出來就是一個圓
Rectangles矩形
void CGContextAddRect (
CGContextRef c,
CGRect rect
);
Quartz2D畫圖練習
- 畫線
- (void)drawRect:(CGRect)rect
{
// 1.獲得圖形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.拼接圖形(路徑)
// 設定線段寬度
CGContextSetLineWidth(ctx, 10);
// 設定線段頭尾部的樣式
CGContextSetLineCap(ctx, kCGLineCapRound);
// 設定線段轉折點的樣式
CGContextSetLineJoin(ctx, kCGLineJoinRound);
/** 第1根線段 **/
// 設定顏色
CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);
// 設定一個起點
CGContextMoveToPoint(ctx, 10, 10);
// 新增一條線段到(100, 100)
CGContextAddLineToPoint(ctx, 100, 100);
// 渲染一次
CGContextStrokePath(ctx);
/** 第2根線段 **/
// 設定顏色
CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);
// 設定一個起點
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 : 同時設定為實心和空心顏色
// setStroke : 設定空心顏色
// setFill : 設定實心顏色
[[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);
// 關閉路徑(連線起點和最後一個點)
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 : 結束角度
// clockwise : 圓弧的伸展方向(0:順時針, 1:逆時針)
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);
// 設定繪圖狀態
CGContextSetLineWidth(ctx, 10);
[[UIColor redColor] set];
CGContextSetLineCap(ctx, kCGLineCapRound);
// 第1根線
CGContextMoveToPoint(ctx, 50, 50);
CGContextAddLineToPoint(ctx, 120, 190);
CGContextStrokePath(ctx);
// 將棧頂的上下文出棧,替換當前的上下文
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預設只會在view第一次顯示的時候呼叫(只能由系統自動呼叫, 不能手動呼叫),如果要重新繪製呼叫 setNeedsDisplay方法。
定時器快速呼叫setNeedsDisplay,如果是一秒呼叫一次可以用NSTimer,如果0.1秒呼叫一次,要用CADisplayLink。每秒重新整理60次。
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- CGMutablePathRef 的使用。
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 1.先建立一個路徑
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.建立一個基於點陣圖的上下文(開啟一個基於點陣圖的上下文)
// size : 新圖片的尺寸
// opaque : YES : 不透明, NO : 透明
// 這行程式碼過後.就相當於常見一張新的bitmap,也就是新的UIImage物件
// 1.建立一個基於點陣圖的上下文(開啟一個基於點陣圖的上下文)
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物件
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 5.結束上下文
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.取得當前的上下文
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);
// 裁剪(後面畫的東西才會受裁剪的影響)
CGContextClip(ctx);
// 6.畫圖
[oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];
// 7.取圖
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 8.結束上下文
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.結束上下文
UIGraphicsEndImageContext();
return newImage;
}
- 條紋背景
// 1.建立一行背景圖片
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.結束上下文
UIGraphicsEndImageContext();
// 5.設定為背景
self.textView.backgroundColor = [UIColor colorWithPatternImage:newImage];
相關文章
- 繪製下載進度(Quartz2D)quartz
- ios之CoreAnimationiOS
- iOS面試之@propertyiOS面試
- realm 之於 iOSiOS
- iOS之KVC KVOiOS
- iOS之widgetiOS
- iOS之NFC使用iOS
- ios之Block研究iOSBloC
- iOS 重繪之drawRectiOS
- iOS之WKWebView封裝iOSWebView封裝
- iOS之Settings BundleiOS
- iOS 動畫之CoreAnimation(CALayer)iOS動畫
- IOS筆記之字典iOS筆記
- IOS筆記之字串iOS筆記字串
- IOS 進階之 WKWebViewiOSWebView
- iOS 開發之— NSURLProtocoliOSProtocol
- iOS之物件複製iOS物件
- iOS之UIWebView的坑iOSUIWebView
- iOS 9之泛型iOS泛型
- iOS逆向之工具使用iOS
- iOS開發之WebViewiOSWebView
- iOS開發之GCDiOSGC
- 調優之iostatiOS
- cacti+nagios之nagios的搭建(三)iOS
- cacti+nagios 之cacti整合nagios(四)iOS
- iOS 底層探索之RunloopiOSOOP
- iOS之Wifi開發探究iOSWiFi
- iOS開發之逆向工程iOS
- iOS 核心圖形之CGFontiOS
- iOS元件化之私有庫iOS元件化
- iOS CoreData排序之 NSFetchRequestiOS排序
- IOS筆記之陣列iOS筆記陣列
- iOS 防止Crash之runtimeiOS
- iOS 持續交付之 FastlaneiOSAST
- iOS開發之避免crashiOS
- iOS殭屍物件之研究iOS物件
- iOS逆向之 程式碼注入iOS
- iOS學習心得之:KVOiOS