CGContext-上下文(畫布)的應(yīng)用

在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.

上下文的用處一般有三種越庇,本文介紹第一種

  1. UIView調(diào)用drawRect:之前系統(tǒng)生成的弹谁,用于界面的繪制漾稀;
  2. UIGraphicsBeginImageContext(), 用于生成圖片;
  3. 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]}];
    
}

最終效果如下:


E8864BF2-347B-4A83-854E-EDC5064B11C7.png

注意所有的操作都是針對(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]}];

}
017BEAC4-6418-4E90-9AC2-FD83CFECA0F4.png

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í)例

畫虛線
  • 效果


    AA377882-6056-47A6-83C7-9A9BA7C6707C.png
  • 代碼及注釋

    //設(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);
畫弧線
  • 效果


    81AD6E35-A85A-42EF-967E-A79D52952DA7.png
  • 代碼
    從當(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);
畫圓弧
  • 效果


    BB569983-B810-4089-890C-116ED2279AA9.png
  • 代碼
CGContextAddArc(ct, 30, 30, 20, 0, M_PI_2*3, 0);
批量添加直線
  • 效果
    直線是連接著的,kCGLineJoinRound 設(shè)置后有連接樣式改變


    24625B11-C3E2-4107-A735-27C73B33A7E2.png
  • 代碼
// 設(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)。

  • 效果


    954AEE47-9A89-4050-B935-7D7E3DE3EC98.png
  • 代碼
// 設(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);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阅羹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子教寂,更是在濱河造成了極大的恐慌捏鱼,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酪耕,死亡現(xiàn)場(chǎng)離奇詭異导梆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)迂烁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門看尼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人盟步,你說(shuō)我怎么就攤上這事藏斩。” “怎么了却盘?”我有些...
    開(kāi)封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵狰域,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我黄橘,道長(zhǎng)兆览,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任塞关,我火速辦了婚禮抬探,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘帆赢。我一直安慰自己小压,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布椰于。 她就那樣靜靜地躺著怠益,像睡著了一般。 火紅的嫁衣襯著肌膚如雪廉羔。 梳的紋絲不亂的頭發(fā)上溉痢,一...
    開(kāi)封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天僻造,我揣著相機(jī)與錄音,去河邊找鬼孩饼。 笑死髓削,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的镀娶。 我是一名探鬼主播立膛,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼梯码!你這毒婦竟也來(lái)了宝泵?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤轩娶,失蹤者是張志新(化名)和其女友劉穎儿奶,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鳄抒,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闯捎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了许溅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓤鼻。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖贤重,靈堂內(nèi)的尸體忽然破棺而出茬祷,到底是詐尸還是另有隱情,我是刑警寧澤并蝗,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布祭犯,位于F島的核電站,受9級(jí)特大地震影響借卧,放射性物質(zhì)發(fā)生泄漏盹憎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一铐刘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧影晓,春花似錦镰吵、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至饵婆,卻和暖如春勺馆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工草穆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灌灾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓悲柱,卻偏偏與公主長(zhǎng)得像锋喜,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豌鸡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容