UIView設(shè)置不觸發(fā)離屏渲染的圓角

當(dāng)我們需要給一個(gè) View 設(shè)置圓角的時(shí)候,一般代碼是這個(gè)樣子

_label.layer.cornerRadius = 10;
_label.layer.masksToBounds = YES;

cornerRadius 和 maskToBounds 獨(dú)立作用的時(shí)候都不會(huì)有太大的性能問(wèn)題,但是當(dāng)他倆結(jié)合在一起,就觸發(fā)了離屏渲染猫缭,
Instrument的 Core Animation 有一個(gè)叫做 Color Offscreen-Rendered Yellow 的選項(xiàng)西采。它會(huì)將已經(jīng)被渲染到屏幕外緩沖區(qū)的區(qū)域標(biāo)注為黃色,下圖中黃色的部分就是離屏渲染的地方冤议。

離屏渲染是什么?

離屏渲染繪制 layer tree 中的一部分到一個(gè)新的緩存里面(這個(gè)緩存不是屏幕师坎,是另一個(gè)地方)恕酸,然后再把這個(gè)緩存渲染到屏幕上面。一般來(lái)說(shuō)胯陋,你需要避免離屏渲染蕊温。因?yàn)檫@個(gè)開(kāi)銷(xiāo)很大袱箱。在屏幕上面直接合成層要比先創(chuàng)建一個(gè)離屏緩存然后在緩存上面繪制,最后再繪制緩存到屏幕上面快很多义矛。這里面有 2 個(gè)上下文環(huán)境的切換(切換到屏幕外緩存環(huán)境发笔,和屏幕環(huán)境)。

解決方案

如果你的 view 不需要讓子視圖超出部分不顯示凉翻,且不需要給 view 的 image 繪制圓角了讨,

可以查看 cornerRadius 屬性的注釋?zhuān)?/p>

By default, the corner radius does not apply to the image in the layer’s contents property; it applies only to the background color and border of the layer. However, setting the masksToBounds property to true causes the content to be clipped to the rounded corners.

這個(gè)屬性會(huì)影響 layer 的背景顏色和 border,所以如下代碼即可避免離屏渲染噪矛。不設(shè)置 masksToBounds 屬性也能設(shè)置圓角量蕊。

view.layer.cornerRadius = radius;
view.layer.backgroundColor = backgroundColor.CGColor;

但如果需要給 view 的 image 繪制圓角,如 UIImageView.image 和 UIButton 的背景圖片艇挨。

則可以用 GraphicsContext 繪制一張帶圓角的 image 給 view 來(lái)避免離屏渲染残炮。

我將這個(gè)過(guò)程封裝了一下

使用 JMRoundedCorner 來(lái)繪制圓角

platform :ios, '7.0'

pod 'JMRoundedCorner'

#import "UIView+RoundedCorner.h"
給 view 設(shè)置一個(gè)圓角邊框
- (void)jm_setCornerRadius:(CGFloat)radius withBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;
給 view 設(shè)置一個(gè)圓角背景顏色
- (void)jm_setCornerRadius:(CGFloat)radius withBackgroundColor:(UIColor *)backgroundColor;
給 view 設(shè)置一個(gè)圓角背景圖
- (void)jm_setCornerRadius:(CGFloat)radius withImage:(UIImage *)image;
給 view 設(shè)置一個(gè) contentMode 模式的圓角背景圖
- (void)jm_setCornerRadius:(CGFloat)radius withImage:(UIImage *)image contentMode:(UIViewContentMode)contentMode;
設(shè)置所有屬性配置出一個(gè)圓角背景圖
- (void)jm_setCornerRadius:(CGFloat)radius withBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth backgroundColor:(UIColor *)backgroundColor backgroundImage:(UIImage *)backgroundImage contentMode:(UIViewContentMode)contentMode;
代碼示例
    _avatarView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 7, 40, 40)];
    [_avatarView jm_setCornerRadius:20 withImage:[UIImage imageNamed:@"avatar.jpg"]];
    [self.contentView addSubview:_avatarView];
//添加占位圖
    _avatarView.image = [placeholderImage jm_imageWithRoundedCornersAndSize:CGSizeMake(60, 60) andCornerRadius:30];

//下載完之后設(shè)置圓角 image
[[SDWebImageManager sharedManager] downloadImageWithURL:_model.avatarURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
    if (image) {
        [_avatarView jm_setCornerRadius:30 withImage:image];
    }
}];

這樣,繪制出了圓角缩滨,也可以避免在大量 view 離屏渲染的時(shí)候拖慢 FPS


將 Demo 下下來(lái)势就,試試使用 JMRoundedCorner 帶來(lái)的順滑提升。

支持通過(guò) JMRadius 設(shè)置4個(gè)角為不同的弧度脉漏,角度優(yōu)先級(jí)為左上 > 右上 > 左下 > 右下苞冯,例如:
[_label jm_setJMRadius:JMRadiusMake(0, 10, 0, 10) withBorderColor:[UIColor redColor] borderWidth:0.5];

聯(lián)系我

感謝

性能上的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):沒(méi)有了離屏渲染,調(diào)整了 image 的像素大小以避免不必要的縮放

缺點(diǎn):會(huì)造成圖層混合侧巨,且因?yàn)橹皇抢L制了一個(gè)帶圓角的圖片舅锄,所以不能使子視圖超出圓角部分不顯示。

注意事項(xiàng)

內(nèi)存會(huì)持續(xù)提升司忱,是正郴史蓿現(xiàn)象,點(diǎn)擊 home 鍵內(nèi)存會(huì)回到正常水平坦仍,并非內(nèi)存泄漏鳍烁,只是繪制的緩存,在內(nèi)存不足時(shí)會(huì)自動(dòng)釋放繁扎。

不要設(shè)置 view 的 backgroundColor幔荒,需要設(shè)置的話可以通過(guò)帶 backgroundColor 參數(shù)的接口進(jìn)行設(shè)置,例如:

- (void)jm_setCornerRadius:(CGFloat)radius withBackgroundColor:(UIColor *)backgroundColor;

控制器輸出以下錯(cuò)誤梳玫,這是 Xcode-7 的 BUG爹梁。

<Error>: CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.

Swift 版本:JMRoundedCornerSwift

更新日志

  • 2016/4/25 1.2.1 版本 : 使用 NSOperationQueue 代替 dispatch_queue,當(dāng)重復(fù)設(shè)置圓角的時(shí)候會(huì)自動(dòng) cancel 上一次操作提澎,感謝 kudocc 的 pull request卫键。

  • 2016/3/12 1.1.0 版本 : 接口帶上了 jm_ 前綴,JMRadius 添加圓角優(yōu)先級(jí)虱朵,經(jīng)過(guò)大量測(cè)試莉炉,解決細(xì)節(jié)上的一些小BUG。

  • 2016/3/3 1.0.3 版本 : 修復(fù) label 里如果沒(méi)有漢字碴犬,文字就不顯示的 BUG絮宁,以及做了使 view 落在像素點(diǎn)上的優(yōu)化。

  • 2016/2/28 1.0.0 版本 :發(fā)布正式版本

  • 2016/2/26 0.0.4 版本 :去掉了 size 參數(shù)及支持 JMRadius 設(shè)置4個(gè)角為不同的弧度

  • 2016/2/25 0.0.3 版本 :去掉了 UIImageView 這個(gè)中間控件

  • 2016/2/24 0.0.2 版本 :支持設(shè)置背景圖片的繪制模式(cotentmode)

  • 2016/2/23 0.0.1 版本 :繪制一個(gè)圓角 image

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末服协,一起剝皮案震驚了整個(gè)濱河市绍昂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偿荷,老刑警劉巖窘游,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異跳纳,居然都是意外死亡忍饰,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)寺庄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)艾蓝,“玉大人,你說(shuō)我怎么就攤上這事斗塘∮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵馍盟,是天一觀的道長(zhǎng)于置。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贞岭,這世上最難降的妖魔是什么八毯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮曹步,結(jié)果婚禮上宪彩,老公的妹妹穿的比我還像新娘。我一直安慰自己讲婚,他們只是感情好尿孔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著筹麸,像睡著了一般活合。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上物赶,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天白指,我揣著相機(jī)與錄音,去河邊找鬼酵紫。 笑死告嘲,一個(gè)胖子當(dāng)著我的面吹牛错维,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播橄唬,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼赋焕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了仰楚?” 一聲冷哼從身側(cè)響起隆判,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎僧界,沒(méi)想到半個(gè)月后侨嘀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捂襟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年咬腕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笆豁。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡郎汪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闯狱,到底是詐尸還是另有隱情煞赢,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布哄孤,位于F島的核電站照筑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瘦陈。R本人自食惡果不足惜凝危,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晨逝。 院中可真熱鬧蛾默,春花似錦、人聲如沸捉貌。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)趁窃。三九已至牧挣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間醒陆,已是汗流浹背瀑构。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刨摩,地道東北人寺晌。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓世吨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親折剃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子另假,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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