在uiview的- (void)drawRect:(CGRect)rect方法之前會(huì)自動(dòng)生成一個(gè)畫布并放在棧頂方仿。通過(guò)UIGraphicsGetCurrentContext()方法獲取當(dāng)前的畫布侨艾。
蘋果原本文檔如下:
The current graphics context is nil
by default. Prior to calling its drawRect:
method, view objects push a valid context onto the stack, making it current. If you are not using a UIView
object to do your drawing, however, you must push a valid context onto the stack manually using the UIGraphicsPushContextfunction.
上下文的用處一般有三種越庇,本文介紹第一種
- UIView調(diào)用drawRect:之前系統(tǒng)生成的弹谁,用于界面的繪制漾稀;
- UIGraphicsBeginImageContext(), 用于生成圖片;
- UIGraphicsBeginPDFContextToFile和UIGraphicsBeginPDFContextToData派近,用于生成PDF;
1蟀悦、畫布的坐標(biāo)轉(zhuǎn)換(Coordinate space transformations)
當(dāng)前變換矩陣CTM(current transformation matrix )用來(lái)改變坐標(biāo)環(huán)境赫编,實(shí)現(xiàn)畫布的平移煤痕、縮放双炕、旋轉(zhuǎn)等操作蚁鳖。
- 畫布平移
/* Translate the current graphics state's transformation matrix (the CTM) by
`(tx, ty)'. */
CG_EXTERN void CGContextTranslateCTM(CGContextRef cg_nullable c,
CGFloat tx, CGFloat ty)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
- 畫布縮放
/* Scale the current graphics state's transformation matrix (the CTM) by
`(sx, sy)'. */
CG_EXTERN void CGContextScaleCTM(CGContextRef cg_nullable c,
CGFloat sx, CGFloat sy)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
- 畫布旋轉(zhuǎn)
/* Rotate the current graphics state's transformation matrix (the CTM) by
`angle' radians. */
CG_EXTERN void CGContextRotateCTM(CGContextRef cg_nullable c, CGFloat angle)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
- 將變換矩陣合并到畫布中
之前有寫過(guò)關(guān)于仿射矩陣變換的簡(jiǎn)書文章熬的,此處就是放射變換方法的一處應(yīng)用場(chǎng)景
/* Concatenate the current graphics state's transformation matrix (the CTM)
with the affine transform `transform'. */
CG_EXTERN void CGContextConcatCTM(CGContextRef cg_nullable c,
CGAffineTransform transform)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
- 獲取當(dāng)前變換矩陣
/* Return the current graphics state's transformation matrix. Returns
CGAffineTransformIdentity in case of inavlid context. */
CG_EXTERN CGAffineTransform CGContextGetCTM(CGContextRef cg_nullable c)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
實(shí)例
將一個(gè)字符串畫到UIView 上向图,偏移tx=10晾咪,ty=10碟嘴,放大2倍的圆,旋轉(zhuǎn)45度鼓拧。
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef ct = UIGraphicsGetCurrentContext();
// 放大 2 倍
CGContextScaleCTM(ct, 2, 2);
// 移動(dòng) 10
CGContextTranslateCTM(ct, 10, 10);
// 旋轉(zhuǎn) 繞45度
CGContextRotateCTM(ct, M_PI_4);
[@"將軍走路" drawInRect:rect withAttributes:@{NSForegroundColorAttributeName:[UIColor blueColor],NSFontAttributeName:[UIFont systemFontOfSize:14],NSBackgroundColorAttributeName:[UIColor cyanColor]}];
}
最終效果如下:
注意所有的操作都是針對(duì)畫布坐標(biāo)的變換,所以并不是中心旋轉(zhuǎn)越妈,而是坐標(biāo)的變換季俩。所以轉(zhuǎn)換的順序不一樣,得到的結(jié)果也不一樣梅掠。把代碼調(diào)一下順序酌住,得到的結(jié)果如下:
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef ct = UIGraphicsGetCurrentContext();
// 旋轉(zhuǎn) 繞45度
CGContextRotateCTM(ct, M_PI_4);
// 放大 2 倍
CGContextScaleCTM(ct, 2, 2);
// 移動(dòng) 10
CGContextTranslateCTM(ct, 10, 10);
[@"將軍走路" drawInRect:rect withAttributes:@{NSForegroundColorAttributeName:[UIColor blueColor],NSFontAttributeName:[UIFont systemFontOfSize:14],NSBackgroundColorAttributeName:[UIColor cyanColor]}];
}
2、上下文的繪圖方式(Path drawing functions)
基本繪制方法
void CGContextDrawPath(CGContextRef cg_nullable c,
CGPathDrawingMode mode)
typedef CF_ENUM (int32_t, CGPathDrawingMode) {
kCGPathFill, //填充
kCGPathEOFill,//奇偶填充
kCGPathStroke,//劃線
kCGPathFillStroke,//填充并劃線
kCGPathEOFillStroke //奇偶填充并劃線
};
蘋果提供的一些方便的繪制方法
- CGContextFillPath
- CGContextEOFillPath
- CGContextStrokePath
- CGContextFillRect
- CGContextFillRects
- CGContextStrokeRect
- CGContextStrokeRectWithWidth
- CGContextClearRect
- CGContextFillEllipseInRect
- CGContextStrokeEllipseInRect
- CGContextStrokeLineSegments
3阎抒、上下文繪制屬性設(shè)置方法(Drawing attribute functions)
void CGContextSetLineWidth(CGContextRef cg_nullable c, CGFloat width)
void CGContextSetLineCap(CGContextRef cg_nullable c, CGLineCap cap)
void CGContextSetLineJoin(CGContextRef cg_nullable c, CGLineJoin join)
void CGContextSetMiterLimit(CGContextRef cg_nullable c, CGFloat limit)
void CGContextSetLineDash(CGContextRef cg_nullable c, CGFloat phase,
const CGFloat * __nullable lengths, size_t count)void CGContextSetFlatness(CGContextRef cg_nullable c, CGFloat flatness)
void CGContextSetAlpha(CGContextRef cg_nullable c, CGFloat alpha)
void CGContextSetBlendMode(CGContextRef cg_nullable c, CGBlendMode mode)
4酪我、路徑的構(gòu)建(Path construction functions)
路徑的基本構(gòu)建方法
void CGContextBeginPath(CGContextRef cg_nullable c)
void CGContextMoveToPoint(CGContextRef cg_nullable c,
CGFloat x, CGFloat y)void CGContextAddLineToPoint(CGContextRef cg_nullable c,
CGFloat x, CGFloat y)void CGContextAddCurveToPoint(CGContextRef cg_nullable c, CGFloat cp1x,
CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y)void CGContextAddQuadCurveToPoint(CGContextRef cg_nullable c,
CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y)void CGContextClosePath(CGContextRef cg_nullable c)
在基本構(gòu)建方法上,蘋果有封裝了一些方便的構(gòu)建方法
- void CGContextAddRect(CGContextRef cg_nullable c, CGRect rect)
- void CGContextAddRects(CGContextRef cg_nullable c,
const CGRect * __nullable rects, size_t count) - void CGContextAddLines(CGContextRef cg_nullable c,
const CGPoint * __nullable points, size_t count) - void CGContextAddEllipseInRect(CGContextRef cg_nullable c, CGRect rect)
- void CGContextAddArc(CGContextRef cg_nullable c, CGFloat x, CGFloat y,
CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise) - void CGContextAddArcToPoint(CGContextRef cg_nullable c,
CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius) - void CGContextAddPath(CGContextRef cg_nullable c,
CGPathRef cg_nullable path)
實(shí)例
畫虛線
-
效果
代碼及注釋
//設(shè)置為虛線
// CGFloat lengths[] = {2,2};
// CGContextSetLineDash(ct, 0, lengths, 2);
//默認(rèn)線條的cap類型就是kCGLineCapButt且叁,而且都哭,虛線必須是這個(gè)類型
// CGContextSetLineCap(ct, kCGLineCapButt);
// CGContextSetLineCap(ct, kCGLineCapRound);
// CGContextSetLineCap(ct, kCGLineCapSquare);
CGPoint points[] = {
CGPointMake(10, 10),CGPointMake(50, 10),
CGPointMake(50, 10),CGPointMake(50, 50),
CGPointMake(50, 50),CGPointMake(10, 50),
CGPointMake(10, 50),CGPointMake(10, 10)
};
// 多點(diǎn)連線方法
CGContextStrokeLineSegments(ct, points, 8);
畫弧線
-
效果
- 代碼
從當(dāng)前點(diǎn)開(kāi)始畫,然后畫一個(gè)圓角。
兩個(gè)點(diǎn)加上當(dāng)前點(diǎn)計(jì)算圓角的兩條切線欺矫,來(lái)確定圓角的角度纱新。
半徑參數(shù)決定圓角的大小
CGContextMoveToPoint(ct, 10, 10);
CGContextAddArcToPoint(ct,80,10,80,30,20);
CGContextAddLineToPoint(ct, 80, 110);
畫圓弧
-
效果
- 代碼
CGContextAddArc(ct, 30, 30, 20, 0, M_PI_2*3, 0);
批量添加直線
-
效果
直線是連接著的,kCGLineJoinRound 設(shè)置后有連接樣式改變
- 代碼
// 設(shè)置連接點(diǎn)為圓角
CGContextSetLineJoin(ct, kCGLineJoinRound);
CGPoint points[] = {
CGPointMake(10, 10),
CGPointMake(50, 10),
CGPointMake(50, 50),
CGPointMake(10, 50),
};
CGContextAddLines(ct, points, 4);
CGContextClosePath(ct);
CGContextStrokePath(ct);
批量畫直線
只是單獨(dú)的畫很多直線穆趴,但是相互并沒(méi)有連接脸爱,利用kCGLineJoinRound 設(shè)置后并沒(méi)有任何反應(yīng)。
-
效果
- 代碼
// 設(shè)置連接點(diǎn)為圓角未妹,但是這些點(diǎn)并沒(méi)有連接
CGContextSetLineJoin(ct, kCGLineJoinRound);
CGPoint points[] = {
CGPointMake(10, 10),CGPointMake(50, 10),
CGPointMake(50, 10),CGPointMake(50, 50),
CGPointMake(50, 50),CGPointMake(10, 50),
CGPointMake(10, 50),CGPointMake(10, 10)
};
// 多點(diǎn)連線方法
CGContextStrokeLineSegments(ct, points, 8);