Core Graphics快速入門

Core Graphics入門

想必每個第一次接觸Core Graphics的開發者都被無數的API、混亂的代碼邏輯折騰得頭疼不已,甚至望而卻步。即使是繪製一個簡單的矩形也看上去非常繁瑣。本文換一個角度,整理一下有關Core Graphics的知識,也算作是這段時間學習的總結。

Core Graphics和UIKit的區別

首先從概念上了解一下:

技術分享

根據蘋果的描述,UIKit是我們最容易也是最常接觸到的框架。絕大多數圖形界面都由UIKit完成。但是UIKit依賴於Core Graphics框架,也是基於Core Graphics框架實現的。如果想要完成某些更底層的功能或者追求極致的性能,那麼依然推薦使用Core Graphics完成。

Core Graphics和UIKit在實際使用中也存在以下這些差異:

  1. Core Graphics其實是一套基於C的API框架,使用了Quartz作爲繪圖引擎。這也就意味着Core Graphics不是面向對象的。
  2. Core Graphics需要一個圖形上下文(Context)。所謂的圖形上下文(Context),說白了就是一張畫布。這一點非常容易理解,Core Graphics提供了一系列繪圖API,自然需要指定在哪裏畫圖。因此很多API都需要一個上下文(Context)參數。
  3. Core Graphics的圖形上下文(Context)是堆棧式的。只能在棧頂的上下文(畫布)上畫圖。
  4. Core Graphics中有一些API,名稱不同卻有着相似的功能,新手只需要掌握一種,並能夠看懂其他的即可。

從一行代碼說起

下面這行代碼應該是很多人最早也是最常寫的代碼。它簡單到我們根本不用思考它的本質。

[self.view addSubview:myButton];

細想一下,UIButton也是繼承自UIView。這段代碼表示,UIKit繪圖的基本思想是通過UIView的疊加實現最終的整體效果。它主要涉及三個內容:畫布、被添加的控件和添加方法。這裏的self.view其實就充當了一張畫布。通過添加不同的UI控件達到最終效果。我們順着這個線索整理一下Core Graphics的編程思路。

Core Graphics的基本使用

爲了使用Core Graphics來繪圖,最簡單的方法就是自定義一個類繼承自UIView,並重寫子類的drawRect方法。在這個方法中繪製圖形。 
Core Graphics必須一個畫布,才能把東西畫在這個畫布上。在drawRect方法方法中,我們可以直接獲取當前棧頂的上下文(Context)。下面的代碼演示了具體操作步驟:

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
}

現在我們已經完成了Core Graphics繪圖的三分之一——創建一個畫布。 
接下來需要考慮被畫上去的東西。這在UIKit中往往是一個UI控件,如Button、Label等。而在Core Graphics中通常表現爲一些基本圖形:三角形、矩形、圓形、以及這些圖形的邊框等。

這通常會涉及到非常多的API,但是如果總結一下不難發現,任何一個要繪製的東西(爲了避免混淆就不稱爲對象了)一定有一個邊框,或者稱爲邊界。在一個幾英寸的屏幕上畫出無界的圖形是不可能的。所以一旦確定了一個邊框,我們就可以設置邊框的各種繪圖屬性、邊框內部區域的繪圖屬性、繪製邊框還是內部區域等。

這就引出了Core Graphics中的路徑(Path)的概念。在前一段代碼的基礎上演示路徑的使用:

- (void)drawSomething{
    CGContextRef context = UIGraphicsGetCurrentContext();//獲取上下文
    CGMutablePathRef path = CGPathCreateMutable();//創建路徑
    CGPathMoveToPoint(path, nil, 20, 50);//移動到指定位置(設置路徑起點)
    CGPathAddLineToPoint(path, nil, 20, 100);//繪製直線(從起始位置開始)
    CGContextAddPath(context, path);//把路徑添加到上下文(畫布)中
}

這裏通過CGPathCreateMutable方法創建了一個路徑。路徑的外在表現就像一條折線。爲了繪製一條路徑,需要用CGPathMoveToPoint函數指定路徑的起點。CGPathAddLineToPoint函數表示在路徑的最後結束點和新的點之間再加一條直線。相當於拓展了原來路徑。通過這樣的簡單的點的累加,可以繪製非常複雜的折線。

但這存在兩個問題:

  1. 繪製矩形等規則多邊形的過程過於繁瑣
  2. 無法繪製曲線。

這些問題Core Graphics早已提供瞭解決辦法。注意到之前我們添加了一個非常普通的自定義路徑。Core Graphics中還提供了很多預先設置好的路徑。不妨在drawRect方法中輸入“cgcontextadd”試試看。

技術分享

這些方法由Core Graphics提供,可以用來繪製圓形、橢圓、矩形、二次曲線等路徑。創建完路徑後還要記得調用CGContextAddPath方法將路徑添加到上下文中。路徑只是我們畫的一條線而已,不把他畫到上,他就沒有什麼卵用。

添加好路徑後,就要開始畫圖了。正如前面提出的問題所說,畫圖的時候需要考慮畫不畫邊框、畫不畫邊框內部的區域,邊框的粗細、顏色、內部區域顏色等問題。Core Graphics提供了另一個方法集合”CGContextSet”來進行這些設置。常見的設置內容如下:

- (void)drawSomething{
    CGContextRef context = UIGraphicsGetCurrentContext();//獲取上下文
    CGMutablePathRef path = CGPathCreateMutable();//創建路徑
    CGPathMoveToPoint(path, nil, 20, 50);//移動到指定位置(設置路徑起點)
    CGPathAddLineToPoint(path, nil, 20, 100);//繪製直線(從起始位置開始)
    CGContextAddPath(context, path);//把路徑添加到上下文(畫布)中

    //設置圖形上下文狀態屬性
    CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1);//設置筆觸顏色
    CGContextSetRGBFillColor(context, 0, 1.0, 0, 1);//設置填充色
    CGContextSetLineWidth(context, 2.0);//設置線條寬度
    CGContextSetLineCap(context, kCGLineCapRound);//設置頂點樣式
    CGContextSetLineJoin(context, kCGLineJoinRound);//設置連接點樣式
    CGFloat lengths[2] = { 18, 9 };
    CGContextSetLineDash(context, 0, lengths, 2);
    CGContextSetShadowWithColor(context, CGSizeMake(2, 2), 0, [UIColor blackColor].CGColor);
    CGContextDrawPath(context, kCGPathFillStroke);//最後一個參數是填充類型
}

設置屬性的前三行就不再解釋了,看一些註釋足矣。頂點指的是路徑的起始點和結束點,連接點指的是路徑中的轉折點(折現纔有)。SetLineDash用於繪製虛線,具體用法參見——《IOS中使用Quartz 2D繪製虛線》。SetShadow方法用於繪製陰影,第二個參數是一個CGSize對象,用於表示陰影偏移量,第三個參數表示模糊度,數值越大,陰影越模糊,第一個參數是一個CGColor,表示陰影顏色,需要由UIColor轉換得到。

至此,我們完成了Core Graphics繪圖的第二步,也是最複雜的一部分:設置繪圖內容。這相當於此前那行代碼的中的UI控件。

設置好了繪圖的屬性之後,就可以調用CGContextDrawPath方法繪圖了。第一個參數表示要在哪一個上下文中繪圖,第二個參數表示填充類型。在填充類型中可以選擇只繪製邊框、只填充、同時繪製邊框和填充內部區域、奇偶規則填充等。

技術分享

從方法名不難看出,但是也需要注意的是,這些設置都是對上下文(context)生效的。這樣會導致,所有的邊框顏色、粗細都一樣。一個簡單的解決辦法就是在需要修改設置之前調用一次CGContextDrawPath方法繪圖。再修改設置,修改設置之後再次繪製。

圖畫完了,還得做一下清理工作。CGPathCreateMutable方法返回的路徑是一個Core Fundation Object。而這並不在ARC的管理範圍之內。所以需要手動釋放對象。

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();//獲取上下文
    CGMutablePathRef path = CGPathCreateMutable();//創建路徑
    /*
        繪圖
    */
    CGPathRelease(path);
}

這樣就完成了Core Graphics繪圖的第三部分——開始繪圖。 
再總結一下使用Core Graphics繪圖的步驟:

  1. 獲取上下文(畫布)
  2. 創建路徑(自定義或者調用系統的API)並添加到上下文中。
  3. 進行繪圖內容的設置(畫筆顏色、粗細、填充區域顏色、陰影、連接點形狀等)
  4. 開始繪圖(CGContextDrawPath)
  5. 釋放路徑(CGPathRelease)
發佈了5 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章