簡介:
Core Graphics 和Quartz 2D的區(qū)別
quartz是一個通用的術(shù)語,用于描述在iOS和MAC OS X ZHONG 整個媒體層用到的多種技術(shù) 包括圖形、動畫、音頻、適配。
Quart 2D 是一組二位繪圖和渲染API,Core Graphic會使用到這組API
Quartz Core 專指Core Animation用到的動畫相關(guān)的庫、API和類
點和像素的對比
系統(tǒng)擁有坐標(biāo)系,如320*480 硬件有retain屏幕和非retain屏:如320*480、640*960
Core Graphics 使用的是系統(tǒng)的坐標(biāo)系來繪制圖片。在分辨率為640*960手機(jī)上繪制圖片時,實際上Core Graphics 的坐標(biāo)是320*480。這個時候每個坐標(biāo)系上的點,實際上擁有兩個像素。
圖形上下文
Core Graphics 使用圖形上下文進(jìn)行工作,這個上下文的作用像畫家的畫布一樣。
在圖形上下文之外是無法繪圖的,我們可以自己創(chuàng)建一個上下文,但是性能和內(nèi)存的使用上,效率是非常低得。
我們可以通過派生一個UIView的子類,獲得它的上下文。在UIView中調(diào)用drawRect:方法時,會自動準(zhǔn)備好一個圖形上下文,可以通過調(diào)用
UIGraphicsGetCurrentContext()來獲取。 因為它是運行期間繪制圖片,我們可以動態(tài)的做一些額外的操作
Core Graphics的優(yōu)點
快速、高效,減小應(yīng)用的文件大小。同時可以自由地使用動態(tài)的、高質(zhì)量的圖形圖像。 使用Core Graphics,可以創(chuàng)建直線、路徑、漸變、文字與圖像等內(nèi)容,并可以做變形處理。
繪制自定義視圖
drawRect:是系統(tǒng)的方法,不要從代碼里面直接調(diào)用 drawRect:,而應(yīng)該使用setNeedsDisplay重繪.
//points:
//指定一個點成為current point,Quartz會跟蹤current point一般執(zhí)行完一個相關(guān)函數(shù)后,current point都會相應(yīng)的改變
CGContextMoveToPoint(CGContextRef??_Nullable c, <#CGFloat x#>, <#CGFloat y#>)
//Lines:
//創(chuàng)建一條直線,從current point到(x,y),然后current point會變成(x,y)
CGContextAddLineToPoint(CGContextRef??_Nullable c, <#CGFloat x#>, <#CGFloat y#>)
//創(chuàng)建多條直線,比如points有兩個點,那么會畫兩條直線,從current point到(x1,y1),
//然后是(x1,y1)到(x2,y2),然后current point會變成points中的最后一個點
//Arcs:
//(x,y)為圓的中心,radius為半徑,startAngle為開始角度,endAngle為結(jié)束角度,clockwise表示,0為順時針,1為逆時針
//假如想創(chuàng)建一個完整的圓圈,那么開始弧度是0,結(jié)束弧度為2PI,因為周長是2PI*r,最后執(zhí)行
//current point就被重置為(x,y),假如當(dāng)前path已經(jīng)存在一個subpath,那么這個函數(shù)執(zhí)行
//的另一個效果是,會有一點直線從current point到弧的起點
CGContextAddArc(<#CGContextRef??_Nullable c#>, <#CGFloat x#>, <#CGFloat y#>, <#CGFloat radius#>, <#CGFloat startAngle#>, <#CGFloat endAngle#>, <#int clockwise#>)
//(x1,y1)(x2,y2),r為半徑,首先畫兩條線分別是current point to(x1,y1)和
//(x1,y1)to (x2,y2)這樣就是出現(xiàn)一個以(x1,y1)為頂點的兩條射線
//然后定義半徑長度,這個半徑是垂直于兩條射線的,這樣就能決定一個圓了,更好的理解下圖,不過
//個人下圖所標(biāo)的tangent point1 的位置是錯誤的。
//最后,函數(shù)執(zhí)行完后,current point就被重置為(x2,y2)
//還有一點要注意的是,假如當(dāng)前path已經(jīng)存在一個subpath,那么這個函數(shù)執(zhí)行的另一種效果是
//會有一條直線,從current point到(x1,y1)
CGContextAddArcToPoint(<#CGContextRef??_Nullable c#>, <#CGFloat x1#>, <#CGFloat y1#>, <#CGFloat x2#>, <#CGFloat y2#>, <#CGFloat radius#>)
/Curves
//畫曲線,一般是一條直線,然后定義幾個控制點,使直線變彎曲
//控制點(x1,y1)(x2,y2)直線的終點(x,y)
//假如第二個控制點(cp2x,cp2y)比(cp1x,cp1y) 更接近current point,那么會形成一個封閉的曲線
CGContextAddCurveToPoint(<#CGContextRef??_Nullable c#>, <#CGFloat cp1x#>, <#CGFloat cp1y#>, <#CGFloat cp2x#>, <#CGFloat cp2y#>, <#CGFloat x#>, <#CGFloat y#>)
//二次曲線函數(shù)
//控制點(px,py) 直線的終點(x,y),執(zhí)行完函數(shù)貌似current point不會變化,沒有具體測試過
CGContextAddQuadCurveToPoint(<#CGContextRef??_Nullable c#>, <#CGFloat cpx#>, <#CGFloat cpy#>, <#CGFloat x#>, <#CGFloat y#>)
//Rectangles
CGContextAddRect(<#CGContextRef??_Nullable c#>, <#CGRect rect#>)
//一次性畫多個矩形,畫矩形有一些特別,current point沒有發(fā)生變化
CGContextAddRects(<#CGContextRef??_Nullable c#>, <#const CGRect * _Nullable rects#>, <#size_t count#>)
//Creat a Path
//調(diào)用函數(shù)CGCcontextBeginPath開始創(chuàng)建路徑,先調(diào)用函數(shù)CGContextMoveToPoint設(shè)置起點
//然后開始畫自己想畫的路徑,注意:
1.Liners,arcs,and curves,是從current point開始的
2.假如想封閉一條路徑,那么調(diào)用函數(shù)CGContextClosePath把當(dāng)前點和起點連接起來
3.當(dāng)畫arcs的時候,Quartz會畫一條線從current point到start point
4.畫矩形的時候不會有從current point到start point的線
5.創(chuàng)建完畢后,必須調(diào)用painting函數(shù),fill or stroke the path,不然不顯示
6.開始創(chuàng)建一個新路徑的時候,使用函數(shù)CGContextBeginPath
//將一個路徑添加到graphics context中
CGContextAddPath(<#CGContextRef??_Nullable c#>, <#CGPathRef??_Nullable path#>)
//stroking:畫出路徑
//Filling:填充路徑的封閉區(qū)域
//影響Stroking的參數(shù),
//線寬
CGContextSetLineWidth(<#CGContextRef??_Nullable c#>, <#CGFloat width#>)
//線轉(zhuǎn)彎樣式,比如圓滑方式
CGContextSetLineJoin(<#CGContextRef??_Nullable c#>, <#CGLineJoin join#>)
//線兩端的樣式,比如兩端變的圓滑
CGContextSetLineCap(<#CGContextRef??_Nullable c#>, <#CGLineCap cap#>)
//虛線相關(guān)
CGContextSetLineDash(<#CGContextRef??_Nullable c#>, <#CGFloat phase#>, <#const CGFloat * _Nullable lengths#>, <#size_t count#>)
//透明度相關(guān)
CGContextSetStrokePattern(<#CGContextRef??_Nullable c#>, <#CGPatternRef??_Nullable pattern#>, <#const CGFloat * _Nullable components#>)
//Stroking的相關(guān)函數(shù)
//Strokes當(dāng)前path.
void CGContextStrokePath (CGContextRef c);
//Strokes 指定的 矩形.
void CGContextStrokeRect (CGContextRef c,CGRect rect);
//Strokes 指定的 矩形, 使用指定的寬度.
void CGContextStrokeRectWithWidth (CGContextRef c,CGRect rect,CGFloat width);
//Strokes 指定的橢圓.
void CGContextStrokeEllipseInRect (CGContextRef context,CGRect rect);
//Strokes 一些直線.
void CGContextStrokeLineSegments (CGContextRef c,const CGPoint points[],size_t count);
//決定是Stroking 還是Filling
void CGContextDrawPath (CGContextRef c,CGPathDrawingMode mode);
線
//1.創(chuàng)建畫布 獲取上下文 2.添加控件 3.添加方法
CGContextRef context = UIGraphicsGetCurrentContext();//創(chuàng)建畫布 獲取上下文
//設(shè)置圖形上下文狀態(tài)屬性
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);//設(shè)置筆觸顏色
CGContextSetRGBFillColor(context, 0, 1.0, 0, 1);//設(shè)置填充色
CGContextSetLineWidth(context, 2.0);//設(shè)置線條寬度
CGPoint lines [] = {
CGPointMake(100, 100),
CGPointMake(150, 150)
};
CGContextAddLines(context, lines, 2);
CGContextDrawPath(context, kCGPathStroke);
圓
#define DEGREES_TO_RADIANS(degrees) ((degrees)*M_PI)/180
//1.創(chuàng)建畫布 獲取上下文 2.添加控件 3.添加方法
CGContextRef context = UIGraphicsGetCurrentContext();//創(chuàng)建畫布 獲取上下文
//設(shè)置圖形上下文狀態(tài)屬性
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);//設(shè)置筆觸顏色
CGContextSetRGBFillColor(context, 0, 1.0, 0, 1);//設(shè)置填充色
CGContextSetLineWidth(context, 2.0);//設(shè)置線條寬度
//2.畫圓弧
CGContextAddArc(context, 100, 100, 50, DEGREES_TO_RADIANS(20), DEGREES_TO_RADIANS(160), 1);
CGContextDrawPath(context, kCGPathStroke);//最后一個參數(shù)是填充類型
圓角矩形
CGContextRef context = UIGraphicsGetCurrentContext();//創(chuàng)建畫布 獲取上下文
//設(shè)置圖形上下文狀態(tài)屬性
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);//設(shè)置筆觸顏色
CGContextSetRGBFillColor(context, 0, 1.0, 0, 1);//設(shè)置填充色
CGContextSetLineWidth(context, 2.0);//設(shè)置線條寬度
float fw = 180;
float fh = 280;
CGContextMoveToPoint(context, fw, fh-20);??// 開始坐標(biāo)右邊開始
CGContextAddArcToPoint(context, fw, fh, fw-20, fh, 10);??// 右下角角度
CGContextAddArcToPoint(context, 120, fh, 120, fh-20, 10); // 左下角角度
CGContextAddArcToPoint(context, 120, 250, fw-20, 250, 10); // 左上角
CGContextAddArcToPoint(context, fw, 250, fw, fh-20, 10); // 右上角
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke); //根據(jù)坐標(biāo)繪制路徑
/*畫矩形*/
CGContextStrokeRect(context,CGRectMake(100, 120, 10, 10));//畫方框
CGContextFillRect(context,CGRectMake(120, 120, 10, 10));//填充框
//矩形,并填棄顏色
CGContextSetLineWidth(context, 2.0);//線的寬度
aColor = [UIColor blueColor];//blue藍(lán)色
CGContextSetFillColorWithColor(context, aColor.CGColor);//填充顏色
aColor = [UIColor yellowColor];
CGContextSetStrokeColorWithColor(context, aColor.CGColor);//線框顏色
CGContextAddRect(context,CGRectMake(140, 120, 60, 30));//畫方框
CGContextDrawPath(context, kCGPathFillStroke);//繪畫路徑
//矩形,并填棄漸變顏色
//第一種填充方式,第一種方式必須導(dǎo)入類庫quartcore并#import ,這個就不屬于在context上畫,而是將層插入到view層上面。那么這里就設(shè)計到Quartz Core 圖層編程了。
CAGradientLayer *gradient1 = [CAGradientLayer layer];
gradient1.frame = CGRectMake(240, 120, 60, 30);
gradient1.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor,
(id)[UIColor grayColor].CGColor,
(id)[UIColor blackColor].CGColor,
(id)[UIColor yellowColor].CGColor,
(id)[UIColor blueColor].CGColor,
(id)[UIColor redColor].CGColor,
(id)[UIColor greenColor].CGColor,
(id)[UIColor orangeColor].CGColor,
(id)[UIColor brownColor].CGColor,nil];
[self.layer insertSublayer:gradient1 atIndex:0];
//第二種填充方式
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGFloat colors[] =
{
1,1,1, 1.00,
1,1,0, 1.00,
1,0,0, 1.00,
1,0,1, 1.00,
0,1,1, 1.00,
0,1,0, 1.00,
0,0,1, 1.00,
0,0,0, 1.00,
};
CGGradientRef gradient = CGGradientCreateWithColorComponents
(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));//形成梯形,漸變的效果
CGColorSpaceRelease(rgb);
//畫線形成一個矩形
//CGContextSaveGState與CGContextRestoreGState的作用
/*
CGContextSaveGState函數(shù)的作用是將當(dāng)前圖形狀態(tài)推入堆棧。之后,您對圖形狀態(tài)所做的修改會影響隨后的描畫操作,但不影響存儲在堆棧中的拷貝。在修改完成后,您可以通過CGContextRestoreGState函數(shù)把堆棧頂部的狀態(tài)彈出,返回到之前的圖形狀態(tài)。這種推入和彈出的方式是回到之前圖形狀態(tài)的快速方法,避免逐個撤消所有的狀態(tài)修改;這也是將某些狀態(tài)(比如裁剪路徑)恢復(fù)到原有設(shè)置的唯一方式。
*/
CGContextSaveGState(context);
CGContextMoveToPoint(context, 220, 90);
CGContextAddLineToPoint(context, 240, 90);
CGContextAddLineToPoint(context, 240, 110);
CGContextAddLineToPoint(context, 220, 110);
CGContextClip(context);//context裁剪路徑,后續(xù)操作的路徑
//CGContextDrawLinearGradient(CGContextRef context,CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,CGGradientDrawingOptions options)
//gradient漸變顏色,startPoint開始漸變的起始位置,endPoint結(jié)束坐標(biāo),options開始坐標(biāo)之前or開始之后開始漸變
CGContextDrawLinearGradient(context, gradient,CGPointMake
(220,90) ,CGPointMake(240,110),
kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(context);// 恢復(fù)到之前的context
CGContextSaveGState(context);
CGContextMoveToPoint(context, 260, 90);
CGContextAddLineToPoint(context, 280, 90);
CGContextAddLineToPoint(context, 280, 100);
CGContextAddLineToPoint(context, 260, 100);
CGContextClip(context);//裁剪路徑
//說白了,開始坐標(biāo)和結(jié)束坐標(biāo)是控制漸變的方向和形狀
CGContextDrawLinearGradient(context, gradient,CGPointMake
(260, 90) ,CGPointMake(260, 100),
kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(context);// 恢復(fù)到之前的context
//下面再看一個顏色漸變的圓
CGContextDrawRadialGradient(context, gradient, CGPointMake(300, 100), 0.0, CGPointMake(300, 100), 10, kCGGradientDrawsBeforeStartLocation);
/*畫扇形和橢圓*/
//畫扇形,也就畫圓,只不過是設(shè)置角度的大小,形成一個扇形
aColor = [UIColor colorWithRed:0 green:1 blue:1 alpha:1];
CGContextSetFillColorWithColor(context, aColor.CGColor);//填充顏色
//以10為半徑圍繞圓心畫指定角度扇形
CGContextMoveToPoint(context, 160, 180);
CGContextAddArc(context, 160, 180, 30,??-60 * PI / 180, -120 * PI / 180, 1);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke); //繪制路徑
//畫橢圓
CGContextAddEllipseInRect(context, CGRectMake(160, 180, 20, 8)); //橢圓
CGContextDrawPath(context, kCGPathFillStroke);
/*畫三角形*/
//只要三個點就行跟畫一條線方式一樣,把三點連接起來
CGPoint sPoints[3];//坐標(biāo)點
sPoints[0] =CGPointMake(100, 220);//坐標(biāo)1
sPoints[1] =CGPointMake(130, 220);//坐標(biāo)2
sPoints[2] =CGPointMake(130, 160);//坐標(biāo)3
CGContextAddLines(context, sPoints, 3);//添加線
CGContextClosePath(context);//封起來
CGContextDrawPath(context, kCGPathFillStroke); //根據(jù)坐標(biāo)繪制路徑
/*畫貝塞爾曲線*/
//二次曲線
CGContextMoveToPoint(context, 120, 300);//設(shè)置Path的起點
CGContextAddQuadCurveToPoint(context,190, 310, 120, 390);//設(shè)置貝塞爾曲線的控制點坐標(biāo)和終點坐標(biāo)
CGContextStrokePath(context);
//三次曲線函數(shù)
CGContextMoveToPoint(context, 200, 300);//設(shè)置Path的起點
CGContextAddCurveToPoint(context,250, 280, 250, 400, 280, 300);//設(shè)置貝塞爾曲線的控制點坐標(biāo)和控制點坐標(biāo)終點坐標(biāo)
CGContextStrokePath(context);