iOS 實現(xiàn)類似擦玻璃效果的一種方法

效果圖

首先談下寫這個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);
  • 在觸摸屏幕的時候(touchesBegantouchesMoved等方法)渔隶,根據(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地址
有錯誤的地方歡迎評論指正

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末找颓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子佛析,更是在濱河造成了極大的恐慌,老刑警劉巖寸莫,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膘茎,死亡現(xiàn)場離奇詭異桃纯,居然都是意外死亡披坏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門伞梯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來着茸,“玉大人,你說我怎么就攤上這事猜绣。” “怎么了掰邢?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵伟阔,是天一觀的道長。 經(jīng)常有香客問我怀估,道長合搅,這世上最難降的妖魔是什么多搀? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任康铭,我火速辦了婚禮赌髓,結果婚禮上催跪,老公的妹妹穿的比我還像新娘夷野。我一直安慰自己,他們只是感情好悯搔,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般抡笼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上平匈,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天藏古,我揣著相機與錄音,去河邊找鬼拧晕。 笑死,一個胖子當著我的面吹牛输玷,可吹牛的內容都是我干的靡馁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼臭墨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了尤误?” 一聲冷哼從身側響起叶圃,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掺冠,沒想到半個月后码党,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斥黑,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡锌奴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹿蜀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡颠焦,死狀恐怖往枣,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情分冈,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布集乔,位于F島的核電站蘑秽,受9級特大地震影響,放射性物質發(fā)生泄漏肠牲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一渡嚣、第九天 我趴在偏房一處隱蔽的房頂上張望肥印。 院中可真熱鬧,春花似錦深碱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽力奋。三九已至,卻和暖如春溅呢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咐旧。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工绩蜻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓词顾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昔驱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內容

  • 轉載:http://www.reibang.com/p/32fcadd12108 每個UIView有一個伙伴稱為l...
    F麥子閱讀 6,216評論 0 13
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復雜腋颠,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,501評論 6 30
  • 每個UIView有一個伙伴稱為layer淑玫,一個CALayer面睛。UIView實際上并沒有把自己畫到屏幕上;它繪制本身...
    shenzhenboy閱讀 3,110評論 0 17
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復雜土涝,今天將帶大家一窺iOS動畫全貌幌墓。在這里你可以看...
    F麥子閱讀 5,113評論 5 13
  • 一冀泻、CAShapelayer 我們知道可以不使用圖片情況下利用CGpath去構建任意形狀的陰影。其實我們也可...
    小貓仔閱讀 1,466評論 0 5