高性能設置圓角,告別離屏渲染

今天來寫一個老生常談的話題衔憨,也是一個面試的高頻問題,我也在面試時不止一次被問到過這個問題——如何高性能的設置圓角袄膏。就用他作為2017年春節(jié)上班之后的第一篇文章践图。

起因

在談及圓角這個話題之前,我們必須先知道系統(tǒng)的API是怎樣去簡單方便的設置圓角的沉馆。以一個imageView控件來舉例码党。

imageView.layer.cornerRadius = CGFloat(10);

簡單粗暴,就能設置圓角斥黑。而在這里的一行代碼揖盘,必須為它洗白一件事情,設置圓角的這行代碼锌奴,本身并不會帶來任何的性能損耗兽狭。如果諸位看官看到此處不相信,大可打開InstrumentsCore Animation來試試看鹿蜀,你就會發(fā)現(xiàn)既沒有Off-Screen Render,也不會出現(xiàn)掉幀的情況箕慧。至于使用Instruments來對UIKit進行分析調試,到時候再寫一篇文章來詳解好了茴恰。

但是颠焦,如果你給一個UILabel也使用了上面的一行代碼,你會發(fā)現(xiàn)這個UILabel并不會有任何的變化往枣,可是我們確實實實在在的為它設置了圓角屬性伐庭。也就是說粉渠,很多時候這個屬性對于內部還有子視圖的控件是無能為力的。所以很多時候似忧,我們會這么來設置圓角渣叛。

imageView.layer.cornerRadius = CGFloat(10);
imageView.layer.masksToBounds = YES;

這時候咱們再打開Instruments去觀察丈秩,惡心的離屏渲染如約而至盯捌。

這里我在稍微贅述一下離屏渲染的概念,什么是離屏渲染呢蘑秽?

討論造成離屏渲染的原因之前饺著,先說明什么是離屏渲染:離屏渲染指的是在圖像在繪制到當前屏幕前,需要先進行一次渲染,之后才繪制到當前屏幕。在第一次渲染時肠牲,GPU(Core Animation)或CPU(Core Graphics)需要額外的一塊內存來進行渲染幼衰,完成后再繪制到屏幕。offscreen到onscreen需要進行上下文切換缀雳,這個切換的性能消耗是昂貴的渡嚣。

因此,我們必須避免不必要的離屏渲染肥印。

造成離屏渲染的原因有:

  • 設置CALayer的cornerRadius识椰,edgeAntialiasingMask,allowsEdgeAntialiasing屬性

  • 把CALayer的maskToBounds設為YES

  • 設置CALayer的shadow屬性

  • 設置CALayer的mask屬性

  • 把CALayer的allowsGroupOpacity屬性設為YES而且opacity小于1

講到這里深碱,大家大可不必對離屏渲染產生巨大的恐慌腹鹉,因為當一個界面的圓角圖片不夠多的時候,對性能的損耗影響基本可以忽略不計敷硅。所以這里的圓角優(yōu)化是針對一屏有很多個圓角的應用來說的功咒。

UIImageView 添加圓角

一般我們最常見的是為UIImageView添加圓角,首先重要的事情放到前面講绞蹦,千萬避免通過重寫drawRect方法來設置圓角力奋,不恰當?shù)氖褂眠@個方法,會導致內存的暴增幽七。其次刊侯,這種方法的同樣會導致離屏渲染。

而一個比較理想的實現(xiàn)思路锉走,是直接截取圖片滨彻。

CGSize size = self.bounds.size;
    CGFloat scale = [UIScreen mainScreen].scale;
    CGSize cornerRadii = CGSizeMake(cornerRadius, cornerRadius);
    
    UIGraphicsBeginImageContextWithOptions(size, YES, scale);
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    if (nil == currentContext) {
        return;
    }
    UIBezierPath *cornerPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:rectCornerType cornerRadii:cornerRadii];
    UIBezierPath *backgroundRect = [UIBezierPath bezierPathWithRect:self.bounds];
    [backgroundColor setFill];
    [backgroundRect fill];
    [cornerPath addClip];
    [self.layer renderInContext:currentContext];
    [self drawBorder:cornerPath];
    UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    if (processedImage) {
        objc_setAssociatedObject(processedImage, &kProcessedImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    self.image = processedImage;

上面這段代碼我只是給出了大致的實現(xiàn)思路,圓角路徑直接用貝塞爾曲線繪制挪蹭,而其中的屬性亭饵,使用了runtime的黑魔法去設置,在Category 給一個現(xiàn)有的類添加屬性梁厉,但是卻不能添加實例變量辜羊,這似乎成為了 Objective-C的一個明顯短板踏兜。然而值得慶幸的是,我們可以通過 Associated Objects來彌補這一不足八秃。

至于完整的Demo和方法庫碱妆,網上已經有很多了,Github動手搜索吧昔驱。

總結

  1. 如果能夠只用 cornerRadius 解決問題疹尾,就不用優(yōu)化。

  2. 如果必須設置 masksToBounds骤肛,可以參考圓角視圖的數(shù)量纳本,如果數(shù)量較少(一頁只有幾個)也可以考慮不用優(yōu)化。

  3. UIImageView 的圓角通過直接截取圖片實現(xiàn)腋颠,其它視圖的圓角可以通過 Core Graphics 畫出圓角矩形實現(xiàn)繁成。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市淑玫,隨后出現(xiàn)的幾起案子巾腕,更是在濱河造成了極大的恐慌,老刑警劉巖絮蒿,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尊搬,死亡現(xiàn)場離奇詭異,居然都是意外死亡歌径,警方通過查閱死者的電腦和手機毁嗦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來回铛,“玉大人狗准,你說我怎么就攤上這事∫鹚啵” “怎么了腔长?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長验残。 經常有香客問我捞附,道長,這世上最難降的妖魔是什么您没? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任鸟召,我火速辦了婚禮,結果婚禮上氨鹏,老公的妹妹穿的比我還像新娘欧募。我一直安慰自己,他們只是感情好仆抵,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布跟继。 她就那樣靜靜地躺著种冬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舔糖。 梳的紋絲不亂的頭發(fā)上娱两,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音金吗,去河邊找鬼十兢。 笑死,一個胖子當著我的面吹牛辽聊,可吹牛的內容都是我干的纪挎。 我是一名探鬼主播期贫,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼跟匆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了通砍?” 一聲冷哼從身側響起玛臂,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎封孙,沒想到半個月后迹冤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡虎忌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年泡徙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膜蠢。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡堪藐,死狀恐怖,靈堂內的尸體忽然破棺而出挑围,到底是詐尸還是另有隱情礁竞,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布杉辙,位于F島的核電站模捂,受9級特大地震影響,放射性物質發(fā)生泄漏蜘矢。R本人自食惡果不足惜狂男,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望品腹。 院中可真熱鬧岖食,春花似錦、人聲如沸珍昨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兔毙,卻和暖如春唾琼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背澎剥。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工锡溯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哑姚。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓祭饭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叙量。 傳聞我的和親對象是個殘疾皇子倡蝙,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內容

  • 目錄 離屏渲染的本質如何設置圓角(三種方法)Shadow 陰影MaskGroupOpacityEdgeAntial...
    路飛_Luck閱讀 1,954評論 0 9
  • 有很多種framework以及很多種方法的組合可以在屏幕上渲染UI元素,我們在這里討論這個過程中發(fā)生的事情绞佩,希望這...
    縱橫而樂閱讀 4,493評論 4 25
  • 繪制像素到屏幕上 answer-huang22 Mar 2014 分享文章 一個像素是如何繪制到屏幕上去的寺鸥?有很多...
    阿貍旅途T恤閱讀 1,637評論 0 7
  • 今天肘交,黑色現(xiàn)實主義先鋒戲劇《埋葬》確定將作為文學劇場演出劇目現(xiàn)身第八屆南鑼戲劇節(jié)的唯一指定劇場蓬蒿笆载,一周前就得到消...
    易鹿閱讀 283評論 0 0
  • We’ve now seen the worst crisis and the deepest recession...
    大立柜閱讀 164評論 0 0