Quartz2D實戰(zhàn)-畫板工具

一直想讓自己每天都能進步全景,但是學習這個事情一直都無法堅持艾蓝,只有自己感覺到了緊迫感,才會敲起代碼粪牲,研究自己以前沒接觸過的知識古瓤,寫博客的目的就是希望能夠和更多的朋友一起討論,促進交流腺阳,共同進步B渚!亭引!

什么是Quartz2D

Quartz2D的API是純C語言的绎速,它是一個二維繪圖引擎,同時支持iOS和Mac系統(tǒng)焙蚓。Quartz2D的API來自于Core Graphics框架纹冤,數(shù)據(jù)類型和函數(shù)基本都以CG作為前綴:CGContextRef洒宝、CGPathRef等。實際開發(fā)中UIKit框架能夠幫我們完成大部分UI萌京,但是有些UI比較復雜雁歌,普通的UIView無法滿足我們的開發(fā)需要,這是就可以利用Quartz2D技術(shù)畫出我們想要的控件知残。

DrawRect:

首先我們需要知道靠瞎,- (void)drawRect:(CGRect)rect方法是在什么時候調(diào)用:

image

我們發(fā)現(xiàn)該方法是在視圖即將展示的時候調(diào)用的,在這個方法中可以獲取到上下文橡庞,將試圖繪制到View上较坛,其實每一個View內(nèi)部都有一個layer屬性,這個方法中就可以了取得一個layer,所以我們繪制的東西其實是繪制到View的layer上扒最,試圖之所以能夠顯示東西,就是因為他的內(nèi)部有一個layer

所以之所以實現(xiàn)drawRect:方法华嘹,是因為吧趣,在這個方法當中可以獲取到圖形上下文,之后耙厚,才會View才會展示出來

- (void)drawRect:(CGRect)rect的調(diào)用時機:

  • 當view第一次顯示到屏幕上時(被加到UIWindow上顯示出來)
  • 調(diào)用view的setNeedsDisplay或者setNeedsDisplayInRect:

圖形上下文(Graphics Context)

  • 保存繪圖信息强挫、繪圖狀態(tài)
  • 決定繪制的輸出目標(繪制到什么地方去?)
    • (輸出目標可以是PDF文件薛躬、Bitmap或者顯示器的窗口上)
  • 相同的一套繪圖序列俯渤,指定不同的Graphics Context,就可將相同的圖像繪制到不同的目標上

繪制好的圖形會保存到圖像上下文中去型宝,圖像上下文中的繪制的圖像又會顯示在我們指定的輸出目標當中

Quartz2D提供的幾種上下文類型:

  • Bitmap Graphics Context
  • PDF Graphics Context
  • Window Graphics Context
  • Layer Graphics Context
  • Printer Graphics Context

Quartz2D繪圖的基本步驟

  1. 獲得圖形上下文
  2. 拼接路徑(下面代碼是搞一條線段八匠,添加矩形、橢圓趴酣、圓弧的代碼可以查看具體的APi梨树,用法基本相同)
  3. 繪制路徑

代碼示例:

CGContextRef ctx = UIGraphicsGetCurrentContext();

CGContextMoveToPoint(ctx, 10, 10);
CGContextAddLineToPoint(ctx, 100, 100);

CGContextStrokePath(ctx); // CGContextFillPath(ctx);

圖形上下文棧的操作

將當前的上下文copy一份,保存到棧頂(那個棧叫做”圖形上下文棧”岖寞,先進后出)

void CGContextSaveGState(CGContextRef c)

將棧頂?shù)纳舷挛某鰲?替換掉當前的上下文

void CGContextRestoreGState(CGContextRef c)

Quartz2D的內(nèi)存管理

  • 使用含有“Create”或“Copy”的函數(shù)創(chuàng)建的對象抡四,使用完后必須釋放,否則將導致內(nèi)存泄露
  • 使用不含有“Create”或“Copy”的函數(shù)獲取的對象仗谆,則不需要釋放
  • 如果retain了一個對象指巡,不再使用時,需要將其release掉
  • 可以使用Quartz 2D的函數(shù)來指定retain和release一個對象隶垮。例如藻雪,如果創(chuàng)建了一個CGColorSpace對象,則使用函數(shù)CGColorSpaceRetain和CGColorSpaceRelease來retain和release對象岁疼。
  • 也可以使用Core Foundation的CFRetain和CFRelease阔涉。注意不能傳遞NULL值給這些函數(shù)

實戰(zhàn)-畫板工具

了解了Quartz2D的基本知識后缆娃,我們就可以運用這些知識,進行一些綜合的練習.

主要代碼如下

  1. 添加手勢
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];

實現(xiàn)方法:

- (void)pan:(UIPanGestureRecognizer *)pan{
    // 獲取當前位置所在點
    CGPoint curP = [pan locationInView:self];
    
    // 筆尖代碼(這段代碼可以去掉瑰排,主要是加了個筆尖贯要,完善功能,提升用戶體驗)
    {
        //獲取偏移量
        //獲取的偏移量是相對于最原始的點
        CGPoint transP = [pan translationInView:self.pointView];
        
        [self.pointView setAlpha:1.f];
        
        CGFloat pointW = self.lineWidth + 5;
        CGPoint pointP = CGPointMake(curP.x - pointW / 2, curP.y - pointW / 2);
        
        [self.pointView setFrame:(CGRect){pointP, self.lineWidth + 5, self.lineWidth + 5}];
        [self.pointView.layer setCornerRadius:self.pointView.bounds.size.width / 2];
        [self.pointView.layer setBorderWidth:1.f];
        [self.pointView.layer setBorderColor:self.lineColor.CGColor];
        
        self.pointView.transform = CGAffineTransformTranslate(self.pointView.transform, transP.x, transP.y);
        
        //清0操作(不讓偏移量進行累加,獲取的是相對于上一次的值,每一次走的值.)
        [pan setTranslation:CGPointMake(0, 0) inView:self.pointView];
    }
    
    if (pan.state == UIGestureRecognizerStateBegan) {
        
        ZJBezierPath *path = [ZJBezierPath bezierPath];
        path.lineWidth = self.lineWidth;
        path.lineJoinStyle = kCGLineJoinRound;
        path.lineCapStyle = kCGLineCapRound;
        path.lineColor = self.lineColor;    // //顏色必須得要在drawRect方法當中進行繪制    繼承系統(tǒng)類,添加屬性我們自己的東西.
        self.path = path;
        
        //設置路徑的起點
        [self.path moveToPoint:curP];
        
        [self.pathArray addObject:path];
        
    } else if (pan.state == UIGestureRecognizerStateChanged){
        
        //添加一根線到當前手指所在的點
        [self.path addLineToPoint:curP];
        
        [self setNeedsDisplay];
        
    } else if (pan.state == UIGestureRecognizerStateEnded){
        [self.pointView setAlpha:0.f];
    }
}

代碼里都有詳細注釋椭住,下面主要講解一些屬性的設置區(qū)別:

lineJoinStyle:有三種樣式

主要是線條的交接處的樣式

typedef CF_ENUM(int32_t, CGLineJoin) {
    kCGLineJoinMiter,
    kCGLineJoinRound,
    kCGLineJoinBevel
};

注意觀察線條的連接處

kCGLineJoinMiter:


image

kCGLineJoinRound:


image

kCGLineJoinBevel


image
  1. 實現(xiàn)- (void)drawRect:(CGRect)rect方法
- (void)drawRect:(CGRect)rect {
    
    for (ZJBezierPath *path in self.pathArray) {
        
      // 繪制路徑
      [path.lineColor set];
      [path stroke];
}

我們發(fā)現(xiàn)我們并沒有在該方法內(nèi)部獲取上下文崇渗、描述路徑等操作就可以將路徑繪制到view上去。重點看[path stroke]方法京郑,其實這個方法內(nèi)部已經(jīng)幫我們實現(xiàn)了繪制視圖的幾個步驟:

  1. 獲取上下文
  2. 描述路徑
  3. 把路徑添加到上下文
  4. 把上下文的內(nèi)容渲染到View的layer

偽代碼如下:

1. 獲取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();

2. 描述路徑
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 10, 10)];
    
3. 把路徑添加到上下文
CGContextAddPath(ctx, path.CGPath);
    
4. 把上下文的內(nèi)容渲染到View的layer
CGContextStrokePath(ctx);

代碼地址

最終效果圖

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宅广,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子些举,更是在濱河造成了極大的恐慌跟狱,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件户魏,死亡現(xiàn)場離奇詭異驶臊,居然都是意外死亡,警方通過查閱死者的電腦和手機叼丑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門关翎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鸠信,你說我怎么就攤上這事纵寝。” “怎么了星立?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵爽茴,是天一觀的道長。 經(jīng)常有香客問我贞铣,道長闹啦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任辕坝,我火速辦了婚禮窍奋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酱畅。我一直安慰自己琳袄,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布纺酸。 她就那樣靜靜地躺著窖逗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪餐蔬。 梳的紋絲不亂的頭發(fā)上碎紊,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天佑附,我揣著相機與錄音,去河邊找鬼仗考。 笑死音同,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的秃嗜。 我是一名探鬼主播权均,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锅锨!你這毒婦竟也來了叽赊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤必搞,失蹤者是張志新(化名)和其女友劉穎必指,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顾画,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡取劫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了研侣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡炮捧,死狀恐怖庶诡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咆课,我是刑警寧澤末誓,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站书蚪,受9級特大地震影響喇澡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜殊校,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一晴玖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧为流,春花似錦呕屎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至莲祸,卻和暖如春蹂安,著一層夾襖步出監(jiān)牢的瞬間椭迎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工田盈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畜号,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓缠黍,卻偏偏與公主長得像弄兜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瓷式,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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

  • --繪圖與濾鏡全面解析 概述 在iOS中可以很容易的開發(fā)出絢麗的界面效果替饿,一方面得益于成功系統(tǒng)的設計,另一方面得益...
    韓七夏閱讀 2,710評論 2 10
  • 什么是Quartz2D 是一個二維的繪圖引擎,同時支持iOS和Mac系統(tǒng) Quartz2D的API是純C語言的,它...
    Mario_ZJ閱讀 574評論 0 1
  • Quartz2D以及drawRect的重繪機制字數(shù)1487 閱讀21 評論1 喜歡1一贸典、什么是Quartz2D Q...
    PurpleWind閱讀 761評論 0 3
  • 我們時常羨慕能夠白頭偕老的人视卢,并渴望自己也有一段這樣的戀情。但在憧憬之余廊驼,我們卻又太在乎自己的感受据过,動不動就與最親...
    蘭兒cx娜閱讀 348評論 0 1
  • 原來光明只不過是, 黑暗玩弄已久的虛偽把戲妒挎。 為什么要知道一切绳锅。 為什么要看清。 所有東西酝掩。 我也無需在意潘鲫。 鏡子...
    詩間行客閱讀 55評論 0 6