寫在前面
關(guān)于在IOS端進(jìn)行原生界面繪制轰传,蘋果開發(fā)文檔里明確提供了幾種方法:
- 使用系統(tǒng)提供的標(biāo)準(zhǔn)視圖盗扒,例如lists, collections, alerts, images, progress bars, tables等。
- 使用Core Animation的圖層刨啸,Core Animation不僅提供了動(dòng)畫的類堡赔,還提供了顯示內(nèi)容的圖層類。
- 使用OpenGL ES设联,這個(gè)框架提供了一套開放標(biāo)準(zhǔn)的圖形繪制庫(kù)善已,主要面向游戲開發(fā)或者需要高幀速率的app。
- 使用UIWebView類展示基于web的圖形界面离例。
很顯然换团,如果你要開發(fā)一套K線框架:
- 第一種方法肯定不適合,因?yàn)槟銢]辦法去用標(biāo)準(zhǔn)的控件來顯示K線宫蛆;
- 第四種使用webview艘包,這樣的話就需要使用百度的echarts,或者還可以使用highcharts
- 所以耀盗,想要開發(fā)原生K線想虎,就只能選擇第二種和第三種方法了
- OpenGL ES框架使用起來比較麻煩,后續(xù)會(huì)單獨(dú)在一篇文章中介紹如何使用
- 所以叛拷,在這里舌厨,就只介紹第二種方法,也就是使用Core Animation
- 其實(shí)忿薇,還有一種辦法裙椭,就是繞過Core Animation躏哩,直接使用Core Graphics進(jìn)行繪制。這個(gè)在后面會(huì)說到揉燃。
Core Animation是什么?
在蘋果的開發(fā)文檔中扫尺,有關(guān)于Core Animation的介紹,點(diǎn)擊這兒你雌。
這里放一張非常經(jīng)典的圖:
Core Animation是一個(gè)圖形渲染和動(dòng)畫的基礎(chǔ)庫(kù)器联,是一個(gè)復(fù)合引擎,職責(zé)就是盡可能快地組合屏幕上不同的可視內(nèi)容婿崭,這個(gè)內(nèi)容是被分解成獨(dú)立的圖層拨拓,存儲(chǔ)在一個(gè)叫圖層樹的體系之中。
Core Animation可以直接用在Max OS X和IOS平臺(tái)上氓栈。
Core Animation的動(dòng)畫執(zhí)行過程都是在后臺(tái)操作的渣磷,不會(huì)阻塞主線程。
Core Animation是直接作用于CALayer授瘦,并非直接作用于UIView醋界。
Core Animation有以下幾個(gè)分類:
- 提供顯示內(nèi)容的圖層類
- 動(dòng)畫和計(jì)時(shí)類
- 布局和約束類
- 事務(wù)類,在原子更新的時(shí)候組合圖層類
CoreAnimation使用
在繪制K線時(shí)提完,主要是使用CALayer的子類CAShapeLayer形纺,它是一個(gè)通過矢量圖形而不是bitmap來繪制的圖層子類。使用時(shí)徒欣,可以直接指定諸如顏色和線寬等屬性逐样,用CGPath來定義線稿繪制的圖形,最后CAShapeLayer就自動(dòng)渲染出來了打肝。
首先先從最簡(jiǎn)單的開始脂新,畫一條線,代碼如下:
//初始化一個(gè)線的圖層
CAShapeLayer *lineLayer = [CAShapeLayer layer];
//初始化一個(gè)描述的路徑
UIBezierPath *linePath = [UIBezierPath bezierPath];
//設(shè)置線段開始的點(diǎn)
[linePath moveToPoint:beginPoint];
//設(shè)置線段結(jié)束的點(diǎn)
//這里也可以添加多個(gè)點(diǎn)
[linePath addLineToPoint:endPoint];
//設(shè)置圖層路徑
lineLayer.path = linePath.CGPath;
//設(shè)置圖層的其他屬性
lineLayer.lineWidth = lineWidth;
lineLayer.strokeColor = lineColor.CGColor;
lineLayer.fillColor = [UIColor clearColor].CGColor;
執(zhí)行結(jié)果如下:
從代碼上可以看到粗梭,繪制線段的步驟很簡(jiǎn)單:
- 初始化一個(gè)圖層
- 初始化用戶線段的路徑
- 添加線段開始的坐標(biāo)點(diǎn)
- 再添加多個(gè)中間的坐標(biāo)點(diǎn)
- 最后添加結(jié)束的坐標(biāo)點(diǎn)
- 把路徑設(shè)置到圖層上去
- 設(shè)置圖層的各個(gè)屬性
其實(shí)現(xiàn)在再想一想K線中的分時(shí)線(如果不了解争便,可以點(diǎn)擊這兒),可以直接用這段代碼來繪制出來断医,當(dāng)然滞乙,不包括分時(shí)線下方的背景顏色,并且得添加多個(gè)坐標(biāo)點(diǎn)孩锡。
畫完一條線后酷宵,再來畫一個(gè)方塊:
//初始化一個(gè)rect
CGRect frameRect = CGRectMake(x, y, width, height);
//初始化一個(gè)圖層
CAShapeLayer *layer = [CAShapeLayer layer];
//初始化一個(gè)描述框的路徑
UIBezierPath *path = [UIBezierPath bezierPathWithRect:frameRect];
//把路徑設(shè)置到圖層中
layer.path = path.CGPath;
//設(shè)置圖層的各個(gè)屬性
layer.strokeColor = strokeColor.CGColor;
layer.fillColor = backColor.CGColor;
執(zhí)行結(jié)果如下:
繪制的步驟也很簡(jiǎn)單:
- 設(shè)置好框的frame
- 然后初始化路徑的時(shí)候,直接把框的frame賦值進(jìn)去
- 初始化一個(gè)圖層
- 把路徑設(shè)置到圖層中
- 設(shè)置圖層的各個(gè)屬性
在這里躬窜,如果留心一下浇垦,其實(shí)就可以想到,框已經(jīng)繪制好了荣挨,那一個(gè)蠟燭也就繪制好了男韧,那繪制多個(gè)框朴摊,一整屏的蠟燭圖不就繪制出來了。(沒留心的此虑,可以點(diǎn)這兒)如果你已經(jīng)理解了上面所說的甚纲,那么我們?cè)贙線框架開發(fā)的道路上已經(jīng)走出一大步。
Core Graphics的使用
上面有第一個(gè)地方說到朦前,繪制界面除了使用Core Animation以外介杆,還可以繞過Core Animation直接使用OpenGL ES或者Core Graphics。
在這里韭寸,介紹一下Core Graphics春哨。Core Graphics是一套基于C的API框架,使用了Quartz作為繪圖引擎恩伺。它提供了低級(jí)別赴背、輕量級(jí)、高保真度的2D渲染晶渠。該框架可以用于基于路徑的繪圖凰荚、變換、顏色管理褒脯、脫屏渲染便瑟,模板、漸變番川、遮蔽胳徽、圖像數(shù)據(jù)管理、圖像的創(chuàng)建爽彤、遮罩以及PDF文檔的創(chuàng)建、顯示和分析缚陷。
和上面一樣适篙,也是從最基礎(chǔ)的一條線開始:
//獲取當(dāng)前上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//開始記錄路徑
CGContextBeginPath(ctx);
//設(shè)置開始坐標(biāo)點(diǎn)
CGContextMoveToPoint(ctx, beginPoint);
//添加坐標(biāo)點(diǎn),或者也可以只添加一個(gè)坐標(biāo)點(diǎn)
CGContextAddLineToPoint(ctx, endPoint);
//結(jié)束記錄路徑
CGContextClosePath(ctx);
//設(shè)置線段寬度
CGContextSetLineWidth(ctx, lineWidth);
//設(shè)置顏色
CGContextSetStrokeColorWithColor(ctx, lineColor.CGColor);
//開始繪制路徑
CGContextStrokePath(ctx);
執(zhí)行效果和上面使用CAShapeLayer繪制線段的效果一樣箫爷。
依次類推嚷节,可以繪制一條線,也就可以繪制一個(gè)框虎锚。
這里說明一下硫痰,代碼中的CGContext 上下文定義了繪制的地方。在使用UIKit時(shí)窜护,上下文是唯一的效斑,UIKit會(huì)維護(hù)著一個(gè)上下文堆棧,而UIKit方法總是繪制到最頂層的上下文中柱徙。
一般使用Core Graphics進(jìn)行繪制缓屠,都會(huì)重寫drawRect方法奇昙,所以這里的上下文就是上下文堆棧最頂層的上下文,使用UIGraphicsGetCurrentContext就可以獲取到敌完。
兩者比較
這里總結(jié)一下储耐,上述介紹了兩種繪制圖形的方式:
- 使用Core Animation的 CAShapeLayer圖層子類
- 使用Core Graphics
那兩種方式有什么區(qū)別呢?
1. CAShapeLayer渲染更快速滨溉。因?yàn)樗褂昧擞布铀偈蚕妫L制同一圖形會(huì)比用Core Graphics快很多。
2. CAShapeLayer更高效使用內(nèi)存晦攒。一個(gè)CAShapeLayer不需要像普通CALayer一樣創(chuàng)建一個(gè)寄宿圖形闽撤,所以無論有多大,都不會(huì)占用太多的內(nèi)存勤家。
3. CAShapeLayer不會(huì)被圖層邊界剪裁掉腹尖,一個(gè) CAShapeLayer 可以在邊界之外繪制。你的圖層路徑不會(huì)像在使用 Core Graphics 的普通 CALayer 一樣被剪裁掉伐脖。
4. CAShapeLayer不會(huì)出現(xiàn)像素化热幔。當(dāng)你給 CAShapeLayer 做3D變換時(shí),它不像一個(gè)有寄宿圖的普通圖層一樣變得像素化讼庇。
其實(shí)最后一點(diǎn)最關(guān)鍵绎巨,因?yàn)樗梅狭薑線框架開發(fā)的業(yè)務(wù)需求。
一旦你實(shí)現(xiàn)了 CALayerDelegate 協(xié)議中的 -drawLayer:inContext: 方法或者 UIView 中的 -drawRect: 方法(其實(shí)就是前者的包裝方法)蠕啄,圖層就創(chuàng)建了一個(gè)繪制上下文场勤,這個(gè)上下文需要的內(nèi)存可從這個(gè)公式得出:圖層寬x圖層高x4字節(jié),寬高的單位均為像素歼跟。對(duì)于一個(gè)在 Retina iPad 上的全屏圖層來說和媳,這個(gè)內(nèi)存量就是 2048x1526x4字節(jié),相當(dāng)于12MB內(nèi)存哈街,圖層每次重繪的時(shí)候都需要重新抹掉內(nèi)存然后重新分配留瞳。
而當(dāng)我們使用K線的時(shí)候,左滑或者右滑時(shí)骚秦,都會(huì)觸發(fā)重新繪制她倘,而每次重繪時(shí)都會(huì)重新獲取一個(gè)繪制上下文。而左滑或者右滑時(shí)作箍,會(huì)高頻率的進(jìn)行重繪硬梁,所以避免不了內(nèi)存的重新分配。
當(dāng)然胞得,這里也不是說Core Graphics效率就很差荧止,只是恰好在這樣的業(yè)務(wù)需求下,會(huì)把某一個(gè)問題放大。并且罩息,不要忘了CAShapeLayer繪制的圖形是直接操作layer嗤详,不會(huì)作用于UIView,更不會(huì)去響應(yīng)用戶的交互瓷炮。