畫板功能的實(shí)現(xiàn)

最近項(xiàng)目中用到了一個(gè)客戶簽字的功能,具體步驟就是客戶簽字確認(rèn)雁社,App把客戶的簽字生成一張PNG圖片上傳到服務(wù)器浴井,服務(wù)器再生成PDF下發(fā)到App展示,所以需要實(shí)現(xiàn)一個(gè)畫板的功能霉撵。

剛開始的時(shí)候是想通過drawRect方法配合UIBezierPath來實(shí)現(xiàn)的磺浙。
具體步驟如下:

  • 創(chuàng)建一個(gè)UIBeizerPath類型的屬性path,用來在touchMove里面記錄手指劃過的軌跡徒坡。創(chuàng)建一個(gè)可變數(shù)組pathArray撕氧,用來儲(chǔ)存多個(gè)UIBeizerPath軌跡。
  • 在touchBegan方法里面把path的初始點(diǎn)移動(dòng)到手指所在位置
  • 在touchMoved方法里面記錄手指移動(dòng)過的軌跡喇完,調(diào)用setNeedsDispaly方法伦泥,該方法會(huì)自動(dòng)調(diào)用drawRect方法,在drawRect方法里面,對(duì)數(shù)組中的UIBeizerPath進(jìn)行繪制不脯。
  • 在touchesEnded方法里面把path屬性添加到數(shù)組里面府怯,并且把path屬性置nil,以便于下次繪制的時(shí)候?qū)ath進(jìn)行初始化防楷。

下面上代碼:

  牺丙、、复局、
- (NSMutableArray *)pathArray {
  if (_pathArray == nil) {
    _ pathArray = [NSMutableArray array];
  }
  return _pathArray;
}

- (UIBezierPath *)path {
  if (_path == nil) {
    _path = [UIBezierPath bezierPath];
    _path.lineWidth = 10;
    _path.lineCapStyle = kCGLineCapRound;
    _path.lineJoinStyle = kCGLineJoinRound;
  }
  return _path;
}

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event{
  UITouch *touch = [touches anyObject];
  CGPoint point = [touch locationInView:self];
  [self.path moveToPoint:point];
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event {
  UITouch *touch = [touches anyObject];
  CGPoint point = [touch locationInView:self];
  [self.path addLineToPoint:point];
  [self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent *)event{
   [self.pathArray addObject:self.path];
   self.path = nil;
}

- (void)drawRect:(CGRect)rect {
   [[UIColor blackColor] setStroke];
   for (UIBezierPath *path in self.pathArray) {
        [path stroke];
   }
   [self.path stroke];
}
 赘被、、肖揣、

做出來的效果如下:

QQ20170914-174520-HD.gif

可以看到功能算是實(shí)現(xiàn)了,但是性能優(yōu)化方面實(shí)在太差浮入,如果手指一直移動(dòng)的話CPU和內(nèi)存都會(huì)暴漲龙优。后來在網(wǎng)上看到了一篇文章內(nèi)存惡鬼drawRect,我才知道了內(nèi)存暴漲的原因事秀,因?yàn)槲抑貙懥薲rawRect方法彤断。而且我在touchMoved方法里面頻繁對(duì)視圖進(jìn)行了重新繪制,這個(gè)渲染的過程會(huì)大量的消耗CPU資源易迹。

我們?cè)谑謾C(jī)屏幕上看到的視圖宰衙,實(shí)際上都是由UIView的屬性CALayer來進(jìn)行繪制和渲染的。而CALayer內(nèi)部有一個(gè)contents屬性睹欲,該屬性默認(rèn)可以傳一個(gè)id類型的對(duì)象供炼。contents也被稱為寄宿圖,當(dāng)我們調(diào)用drawRect方法的時(shí)候窘疮,系統(tǒng)就會(huì)為視圖分配一個(gè)寄宿圖袋哼,這個(gè)寄宿圖的像素尺寸等于視圖大小乘以contentsScale(這個(gè)屬性與屏幕分辨率有關(guān),我們的畫板程序在不同模擬器下呈現(xiàn)不同的內(nèi)存消耗量也是因?yàn)樵撝挡煌┑闹嫡⑸馈K蕴喂幔还苣愕膁rawRect方法里面有沒有代碼,實(shí)際上都會(huì)對(duì)內(nèi)存有所損耗蔚出。

作者在文章中也提出了解決方法弟翘,就是直接使用專有圖層CAShapeLayer。CAShaperLayer是一個(gè)通過矢量圖形而不是bitmap來繪制的圖層子類骄酗。用CGPath來定義想要繪制的圖形稀余,CAShapeLayer會(huì)自動(dòng)渲染。與直接使用CoreGraphics繪制layer對(duì)比酥筝,CAShapeLayer有以下優(yōu)點(diǎn):

  • 渲染快速滚躯。CAShapeLayer使用了硬件加速,繪制同一圖形比用CoreGraphics快很多。
  • 高效使用內(nèi)存掸掏。一個(gè)CAShapeLayer不需要像普通CALayer一樣創(chuàng)建一個(gè)寄宿圖形茁影,所以無論有多大,都不會(huì)占用太多內(nèi)存丧凤。
  • 不會(huì)被圖層邊界裁剪掉(這個(gè)我在寫畫板的過程中也發(fā)現(xiàn)了募闲,就算手指移動(dòng)的軌跡超出了畫板的范圍,也能繪制出軌跡愿待,設(shè)置視圖的maskToBounds就可以解決了)浩螺。
  • 不會(huì)出現(xiàn)像素化。

OK仍侥,既然知道了替代方法要出,接下來就是擼起袖子干了,步驟如下:

  • 創(chuàng)建一個(gè)UIBezierPath類型的屬性path农渊,用來記錄手指劃過的軌跡患蹂。創(chuàng)建一個(gè)CAShapeLayer類型的屬性shapeLayer,用來渲染軌跡砸紊。
  • 在touchBegan方法里面把path的初始點(diǎn)移動(dòng)到手指所在位置传于。
  • 在touchMoved方法里面用path記錄手指的移動(dòng)軌跡,并且把path賦值給CAShapeLayer進(jìn)行渲染醉顽。
  • 在touchEnded方法里面把shaperLayer和path置nil沼溜,以便于畫下一條軌跡的時(shí)候?qū)λ鼈冞M(jìn)行初始化。

代碼:

   游添、系草、、
- (CAShapeLayer *)shapeLayer{
  if (_shapeLayer == nil) {
    _shapeLayer = [CAShapeLayer layer];
    _shapeLayer.strokeColor = [UIColor blackColor].CGColor;
    _shapeLayer.fillColor = [UIColor clearColor].CGColor;
    _shapeLayer.lineJoin = kCALineJoinRound;
    _shapeLayer.lineCap = kCALineCapRound;
    _shapeLayer.lineWidth = 10;
    [self.layer addSublayer:_shapeLayer];
   }
   return _shapeLayer;
 }

- (UIBezierPath *)path{
  if (_path == nil) {
    _path = [UIBezierPath bezierPath];
    _path.lineWidth = 10;
  }
  return _path;
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  UITouch *touch = [touches anyObject];
  CGPoint point = [touch locationInView:self];
  [self.path addLineToPoint:point];
  self.shapeLayer.path = self.path.CGPath;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  UITouch *touch = [touches anyObject];
  CGPoint point = [touch locationInView:self];
  [self.path moveToPoint:point];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  self.shapeLayer = nil;
  self.path = nil;
}
否淤、悄但、、

現(xiàn)在我們?cè)賮砜匆幌聝?nèi)存:

QQ20170915-142931-HD.gif

基本沒有什么大的損耗了石抡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末檐嚣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子啰扛,更是在濱河造成了極大的恐慌嚎京,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隐解,死亡現(xiàn)場(chǎng)離奇詭異鞍帝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)煞茫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門帕涌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摄凡,“玉大人,你說我怎么就攤上這事蚓曼∏自瑁” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵纫版,是天一觀的道長(zhǎng)床绪。 經(jīng)常有香客問我,道長(zhǎng)其弊,這世上最難降的妖魔是什么癞己? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮梭伐,結(jié)果婚禮上痹雅,老公的妹妹穿的比我還像新娘。我一直安慰自己糊识,他們只是感情好练慕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著技掏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪项鬼。 梳的紋絲不亂的頭發(fā)上哑梳,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音绘盟,去河邊找鬼鸠真。 笑死,一個(gè)胖子當(dāng)著我的面吹牛龄毡,可吹牛的內(nèi)容都是我干的吠卷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼沦零,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼祭隔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起路操,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤疾渴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后屯仗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搞坝,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年魁袜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了桩撮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敦第。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖店量,靈堂內(nèi)的尸體忽然破棺而出芜果,到底是詐尸還是另有隱情,我是刑警寧澤垫桂,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布师幕,位于F島的核電站,受9級(jí)特大地震影響诬滩,放射性物質(zhì)發(fā)生泄漏霹粥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一疼鸟、第九天 我趴在偏房一處隱蔽的房頂上張望后控。 院中可真熱鬧,春花似錦空镜、人聲如沸浩淘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽张抄。三九已至,卻和暖如春洼怔,著一層夾襖步出監(jiān)牢的瞬間署惯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工镣隶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留极谊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓安岂,卻偏偏與公主長(zhǎng)得像轻猖,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子域那,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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