K線開發(fā)之CoreGraphics和CoreAnimation的比較

寫在前面

關(guān)于在IOS端進(jìn)行原生界面繪制,蘋果開發(fā)文檔里明確提供了幾種方法:

  1. 使用系統(tǒng)提供的標(biāo)準(zhǔn)視圖,例如lists, collections, alerts, images, progress bars, tables等。
  2. 使用Core Animation的圖層,Core Animation不僅提供了動畫的類,還提供了顯示內(nèi)容的圖層類。
  3. 使用OpenGL ES,這個框架提供了一套開放標(biāo)準(zhǔn)的圖形繪制庫,主要面向游戲開發(fā)或者需要高幀速率的app。
  4. 使用UIWebView類展示基于web的圖形界面。

很顯然,如果你要開發(fā)一套K線框架:

  • 第一種方法肯定不適合,因為你沒辦法去用標(biāo)準(zhǔn)的控件來顯示K線;
  • 第四種使用webview,這樣的話就需要使用百度的echarts,或者還可以使用highcharts
  • 所以,想要開發(fā)原生K線,就只能選擇第二種和第三種方法了
  • OpenGL ES框架使用起來比較麻煩,后續(xù)會單獨在一篇文章中介紹如何使用
  • 所以,在這里,就只介紹第二種方法,也就是使用Core Animation
  • 還有一種辦法,就是繞過Core Animation,直接使用Core Graphics進(jìn)行繪制。這個在后面會說到。

它是什么

要使用它,就的先了解一下它是什么?

在蘋果的開發(fā)文檔中,有關(guān)于Core Animation的介紹,點擊這兒。

這里放一張非常經(jīng)典的圖:

Core Animation

Core Animation是一個圖形渲染和動畫的基礎(chǔ)庫,是一個復(fù)合引擎,職責(zé)就是盡可能快地組合屏幕上不同的可視內(nèi)容,這個內(nèi)容是被分解成獨立的圖層,存儲在一個叫圖層樹的體系之中。
Core Animation可以直接用在Max OS X和IOS平臺上。
Core Animation的動畫執(zhí)行過程都是在后臺操作的,不會阻塞主線程。
Core Animation是直接作用于CALayer,并非直接作用于UIView。
Core Animation有以下幾個分類:

  • 提供顯示內(nèi)容的圖層類
  • 動畫和計時類
  • 布局和約束類
  • 事務(wù)類,在原子更新的時候組合圖層類

CoreAnimation使用

在繪制k線時,主要是使用CALayer的子類CAShapeLayer,它是一個通過矢量圖形而不是bitmap來繪制的圖層子類。使用時,可以直接指定諸如顏色和線寬等屬性,用CGPath來定義線稿繪制的圖形,最后CAShapeLayer就自動渲染出來了。

首先先從最簡單的開始,畫一條線,代碼如下:

    //初始化一個線的圖層
    CAShapeLayer *lineLayer = [CAShapeLayer layer];
    //初始化一個描述的路徑
    UIBezierPath *linePath = [UIBezierPath bezierPath];
    //設(shè)置線段開始的點
    [linePath moveToPoint:beginPoint];
    //設(shè)置線段結(jié)束的點
    //這里也可以添加多個點
    [linePath addLineToPoint:endPoint];
    //設(shè)置圖層路徑
    lineLayer.path = linePath.CGPath;
    //設(shè)置圖層的其他屬性
    lineLayer.lineWidth = lineWidth;
    lineLayer.strokeColor = lineColor.CGColor;
    lineLayer.fillColor = [UIColor clearColor].CGColor;

執(zhí)行結(jié)果如下:

執(zhí)行結(jié)果

從代碼上可以看到,繪制線段的步驟很簡單:

  1. 初始化一個圖層
  2. 初始化用戶線段的路徑
  3. 添加線段開始的坐標(biāo)點
  4. 再添加多個中間的坐標(biāo)點
  5. 最后添加結(jié)束的坐標(biāo)點
  6. 把路徑設(shè)置到圖層上去
  7. 設(shè)置圖層的各個屬性

其實現(xiàn)在再想一想K線中的分時線(如果不了解,可以點擊這兒),可以直接用這段代碼來繪制出來,當(dāng)然,不包括分時線下方的背景顏色,并且得添加多個坐標(biāo)點。

畫完一條線后,再來畫一個方塊:

    //初始化一個rect
    CGRect frameRect = CGRectMake(x, y, width, height);
    //初始化一個圖層
    CAShapeLayer *layer = [CAShapeLayer layer];
    //初始化一個描述框的路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:frameRect];
    //把路徑設(shè)置到圖層中
    layer.path = path.CGPath;
    //設(shè)置圖層的各個屬性
    layer.strokeColor = strokeColor.CGColor;
    layer.fillColor = backColor.CGColor;

執(zhí)行結(jié)果如下:

執(zhí)行結(jié)果

繪制的步驟也很簡單:

  1. 設(shè)置好框的frame
  2. 然后初始化路徑的時候,直接把框的frame賦值進(jìn)去
  3. 初始化一個圖層
  4. 把路徑設(shè)置到圖層中
  5. 設(shè)置圖層的各個屬性

在這里,如果留心一下,其實就可以想到,框已經(jīng)繪制好了,那一個蠟燭也就繪制好了,那繪制多個框,一整屏的蠟燭圖不就繪制出來了。(沒留心的,可以點這兒)如果你已經(jīng)理解了上面所說的,那么我們在K線框架開發(fā)的道路上已經(jīng)走出一大步。

Core Graphics的使用

上面有第一個地方說到,繪制界面除了使用Core Animation以外,還可以繞過Core Animation直接使用OpenGL ES或者Core Graphics。

在這里,介紹一下Core Graphics。Core Graphics是一套基于C的API框架,使用了Quartz作為繪圖引擎。它提供了低級別、輕量級、高保真度的2D渲染。該框架可以用于基于路徑的繪圖、變換、顏色管理、脫屏渲染,模板、漸變、遮蔽、圖像數(shù)據(jù)管理、圖像的創(chuàng)建、遮罩以及PDF文檔的創(chuàng)建、顯示和分析。

和上面一樣,也是從最基礎(chǔ)的一條線開始:

    //獲取當(dāng)前上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //開始記錄路徑
    CGContextBeginPath(ctx);
    //設(shè)置開始坐標(biāo)點
    CGContextMoveToPoint(ctx, beginPoint);
    //添加坐標(biāo)點,或者也可以只添加一個坐標(biāo)點
    CGContextAddLineToPoint(ctx, endPoint);
    //結(jié)束記錄路徑
    CGContextClosePath(ctx);
    //設(shè)置線段寬度
    CGContextSetLineWidth(ctx, lineWidth);
    //設(shè)置顏色
    CGContextSetStrokeColorWithColor(ctx, lineColor.CGColor);
    //開始繪制路徑
    CGContextStrokePath(ctx);

執(zhí)行效果和上面使用CAShapeLayer繪制線段的效果一樣。

依次類推,可以繪制一條線,也就可以繪制一個框。

這里說明一下,代碼中的CGContext 上下文定義了繪制的地方。在使用UIKit時,上下文是唯一的,UIKit會維護(hù)著一個上下文堆棧,而UIKit方法總是繪制到最頂層的上下文中。

一般使用Core Graphics進(jìn)行繪制,都會重寫drawRect方法,所以這里的上下文就是上下文堆棧最頂層的上下文,使用UIGraphicsGetCurrentContext就可以獲取到。

兩者比較

這里總結(jié)一下,上述介紹了兩種繪制圖形的方式:

  1. 使用Core Animation的 CAShapeLayer圖層子類
  2. 使用Core Graphics

那兩種方式有什么區(qū)別呢?

  1. CAShapeLayer渲染更快速。因為它使用了硬件加速,繪制同一圖形會比用Core Graphics快很多。
  2. CAShapeLayer更高效使用內(nèi)存。一個CAShapeLayer不需要像普通CALayer一樣創(chuàng)建一個寄宿圖形,所以無論有多大,都不會占用太多的內(nèi)存。
  3. CAShapeLayer不會被圖層邊界剪裁掉,一個 CAShapeLayer 可以在邊界之外繪制。你的圖層路徑不會像在使用 Core Graphics 的普通 CALayer 一樣被剪裁掉。
  4. CAShapeLayer不會出現(xiàn)像素化。當(dāng)你給 CAShapeLayer 做3D變換時,它不像一個有寄宿圖的普通圖層一樣變得像素化。

其實最后一點最關(guān)鍵,因為它正好符合了k線框架開發(fā)的業(yè)務(wù)需求,一語中的。

一旦你實現(xiàn)了 CALayerDelegate 協(xié)議中的 -drawLayer:inContext: 方法或者 UIView 中的 -drawRect: 方法(其實就是前者的包裝方法),圖層就創(chuàng)建了一個繪制上下文,這個上下文需要的內(nèi)存可從這個公式得出:圖層寬x圖層高x4字節(jié),寬高的單位均為像素。對于一個在 Retina iPad 上的全屏圖層來說,這個內(nèi)存量就是 2048x1526x4字節(jié),相當(dāng)于12MB內(nèi)存,圖層每次重繪的時候都需要重新抹掉內(nèi)存然后重新分配。

而當(dāng)我們使用k線的時候,左滑或者右滑時,都會觸發(fā)重新繪制,而每次重繪時都會重新獲取一個繪制上下文。而左滑或者右滑時,會高頻率的進(jìn)行重繪,所以避免不了內(nèi)存的重新分配。

當(dāng)然,這里也不是說Core Graphics效率就很差,只是恰好在這樣的業(yè)務(wù)需求下,會把某一個問題放大。并且,不要忘了CAShapeLayer繪制的圖形是直接操作layer,不會作用于UIView,更不會去響應(yīng)用戶的交互。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容