首先談下寫這個demo的靈感來源(扯談)玖喘,是無意在github上看到這個東西(以下簡稱大神),感覺有意思就拿下來看看贬派,結果看了好幾遍也沒完全看懂澎媒,再結合自己之前學的東西感覺不用這么復雜也能實現(xiàn)同樣的效果,于是乎就開始動手了旱幼。
大體思路
動手前先想了下思路,就是利用母雞哥講的涂鴉
+ 設置layer的mask
的方式冬三,這樣做可以說是非常簡單了缘缚。然后就用了半下午的時間寫完了,效果基本和大神寫得那個一樣桥滨,而且對比了下代碼量,我寫得真是簡單明了呀蒲每,用了不到大神代碼量一半的代碼就完成了同樣的功能喻括,心情愉悅。然后就想開開心心的把代碼上傳github唬血,上傳之前心里總感覺不太對唤崭,這么簡單就能實現(xiàn)脖律,大神為什么還要寫得那么麻煩,而且還用到了很多c和c++的東西芦疏。然后我又跑了大神的應用看了看cpu利用率(我用5s跑的)膏孟,大約最高保持在百分這十幾眯分,感覺有點高但也可以柒桑,再跑我自己寫得,令我大吃了一驚飘诗,隨便劃幾下就百分之40+了界逛,這么個小東西耗這么多cpu那這也太low了,怎么還好意思上傳到github上呢息拜。。喳瓣。
bug測試及解
經(jīng)過測試赞别,發(fā)現(xiàn)是母雞哥講的涂鴉有性能問題,雖然代碼簡單仿滔,思路清晰,但是隨著觸摸屏幕的點不斷增加鞠绰,整個繪制復雜度也是呈指數(shù)上升飒焦,導致的結果就是耗cpu非常嚴重。所以關于繪制圖片我不得不再想其它的方法實現(xiàn)。但是我冥想了一天時間也沒有找到好的方法降低繪制的復雜度(除了大神的那個方法),當然最后的解決方法也非常簡單了志电,沒錯,就是copy大神的方法??例朱。下面著重介紹下大神的解決涂鴉cpu消耗問題方法(這里是重點):
- 圖形上下文:不再用layer的默認的圖形上下文了(也就是在
drawRect
方法里面用UIGraphicsGetCurrentContext()
獲取的)鱼蝉,而是自己創(chuàng)建一個全局的bitmap上下文
self.imageContext = CGBitmapContextCreate(0, frame.size.width, frame.size.height, 8, frame.size.width * 4, self.colorSpace, kCGImageAlphaPremultipliedLast);
CGContextSetStrokeColorWithColor(self.imageContext,[UIColor redColor].CGColor);
CGContextSetFillColorWithColor(self.imageContext, [UIColor redColor].CGColor);
CGContextTranslateCTM(self.imageContext, 0.0f, self.bounds.size.height);
CGContextScaleCTM(self.imageContext, 1.0f, -1.0f);
- 在觸摸屏幕的時候(
touchesBegan
、touchesMoved
等方法)渔隶,根據(jù)觸摸的位置洁奈,每兩個點之間連線,繪制到上面建立的圖形上下文當中利术,這樣就是隨著觸摸屏幕,隨著往圖形上下文繪制被冒,不會把之前已經(jīng)繪制的再重新添加繪制轮蜕,解決了性能消耗過高的問題。
#pragma mark - touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
[self reCreateImageWithTouchDict:@{@"touch":touch, @"lineWidth":@(touch.majorRadius)}];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
[self reCreateImageWithTouchDict:@{@"touch":touch, @"lineWidth":@(touch.majorRadius)}];
}
- (UIImage *)reCreateImageWithTouchDict:(NSDictionary *)touchDict{
UITouch* touch = touchDict[@"touch"];
CGFloat lineWidth = [touchDict[@"lineWidth"] floatValue] * 0.5;
if (lineWidth < 1.0) {
lineWidth = 10;
}
if (touch) {
CGPoint point = [touch locationInView:touch.view];
if (touch.phase == UITouchPhaseBegan) {
CGRect rect = CGRectMake(point.x - lineWidth, point.y - lineWidth, lineWidth*2, lineWidth*2);
CGContextAddEllipseInRect(self.imageContext, rect);
CGContextFillPath(self.imageContext);
[self.points removeAllObjects];
[self.points addObject:[NSValue valueWithCGPoint:point]];
}else if (touch.phase == UITouchPhaseMoved){
[self.points addObject:[NSValue valueWithCGPoint:point]];
if (self.points.count > 2) {
CGContextSetLineCap(self.imageContext, kCGLineCapRound);
CGContextSetLineWidth(self.imageContext, 2 * lineWidth);
do{
CGPoint point0 = [(NSValue *)self.points[0] CGPointValue];
CGPoint point1 = [(NSValue *)self.points[1] CGPointValue];
CGContextMoveToPoint(self.imageContext, point0.x, point0.y);
CGContextAddLineToPoint(self.imageContext, point1.x, point1.y);
[self.points removeObjectAtIndex:0];
}while (self.points.count > 2);
}
}
CGContextStrokePath(self.imageContext);
}
CGImageRef cgImage = CGBitmapContextCreateImage(self.imageContext);
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return image;
}
最后實現(xiàn)
最后設置mask就非常簡單了,設置我們將要顯示的圖片(那張清晰的)的layer的mask為上面通過繪制生成的image的layer税课,這樣只有繪制過的位置才能看到將要顯示的圖片,功能就完成了??韩玩,我感覺利用這個小技巧可以做很多有趣的東西(類似刮獎等)
CALayer *mask = [CALayer layer];
mask.contents = (id)image.CGImage;
mask.anchorPoint = CGPointZero;
mask.frame = self.bounds;
self.imageView.layer.mask = mask;
self.imageView.layer.masksToBounds = YES;
最后
別忘記釋放相關內存
- (void)dealloc{
if (_imageContext != NULL) {
CFRelease(_imageContext);
}
if (_colorSpace != NULL) {
CFRelease(_colorSpace);
}
}
最后的最后 奉上demo地址
有錯誤的地方歡迎評論指正