iOS一個簡單的設(shè)置圓角不引起性能問題的分類

寫在前面

iOS設(shè)置圓角的性能探究已經(jīng)是一個老生常談的問題了朴译,眾所周知耐齐,如果直接使用layercornerRadius + masksToBounds雖然可以很方便的完成圓角設(shè)置埃撵,但會引起離屏渲染堕虹,導(dǎo)致性能問題否纬,在列表視圖中過多的圓角設(shè)置就會導(dǎo)致滑動卡頓仍秤,現(xiàn)在主流的方案就是在獲取圖片的一刻開啟異步線程對圖片進(jìn)行相應(yīng)的圓角處理,把圖片處理成想要的圖片在返回主線程進(jìn)行顯示彼宠,想要便捷的達(dá)成此目的推薦YY大神的YYWebImage鳄虱,其在獲取圖片的時候的時候提供了一個transformblock,在此block中你可以完成圖片的處理工作凭峡,但是在實(shí)際的使用中拙已,我覺得第二種方案還是有些不方便的地方,具體如下:

1摧冀、對于網(wǎng)絡(luò)圖片倍踪,大多數(shù)要提前設(shè)置展位圖,如果美工沒有提供圓角占位圖片索昂,你需要相應(yīng)的對占位圖片進(jìn)行圓角處理建车;

2、對于混合視圖需要圓角的楼镐,比如下圖癞志,圖片上有一個Label,label也需要圓角化框产,你也得對label進(jìn)行單獨(dú)的處理(這里我有個小tip:如果必須使用這種方式凄杯,我的做法是生成一張左下角和右下角圓角化的黑色背景圖片错洁,然后使用colorWithPatternImage 將圖片設(shè)置label的背景色,這樣你不需要為這個黑色的圓角地圖另外創(chuàng)建一個視圖)

圖片上有Label.png

3戒突、如果多處需要重復(fù)使用同一個圖片地址屯碴,使用YYWebImage時,其會將tranform后的圖片緩存起來膊存,所以就會出現(xiàn)导而,如果你在一個地方圓角化了該圖片,在另一個地方使用時依然會是圓角化的圖片隔崎,這顯然在有時候是不滿足需求的今艺,不過你可以使用不同的YYWebImageManager來管理相同圖片地址而需要不同transform的圖片;

綜上所述爵卒,雖然可以通過一些方式解決上述問題虚缎,如果有一個性能優(yōu)秀且能避免上訴問題產(chǎn)生的圓角化方案就更好了。

我的方案

要避免上述問題钓株,我們就不能從修改圖片入手了实牡,還是需要從視圖層次入手,我采取的方案其實(shí)也相當(dāng)簡單轴合,如果某個視圖需要圓角化创坞,我只需要在該視圖上添加一個子layer到最上層,用于遮蓋該視圖及其子視圖受葛,設(shè)置layer的圖片為剛好能夠遮蓋成所需圓角樣子并且圖片顏色剛好是該視圖父視圖的背景顏色就達(dá)到達(dá)到想要的效果的题涨,由于該遮罩layer在最上層,所以對于上面所提到的第二個缺點(diǎn)中的Label总滩,也順帶著遮罩了携栋,所以無需再次處理,當(dāng)然由于我們是在視圖層次而非圖片層次處理的圓角咳秉,上面的第一個和第三個缺點(diǎn)也不存在了,這樣其實(shí)很簡單的解決的上訴三個缺點(diǎn)鸯隅,下面來看看相關(guān)的代碼:

1澜建、首先是繪制遮蓋layer的圖層圖片,當(dāng)然我們可以讓美工切圖給我們蝌以,但是如果對于每個尺寸的視圖都去切圖的話炕舵,工作量就相應(yīng)增大了,其實(shí)我們值需要繪制一張如下的圖片跟畅,如果是空白咽筋,請點(diǎn)擊圖片查看

帶邊框.png
不帶邊框.png

先來看看繪制代碼

/**我創(chuàng)建了一個分類用于創(chuàng)建相應(yīng)的遮罩圖片*/
@implementation UIImage (XWAddForRoundedCorner)

/**提供一個在一個指定的size中繪制圖片的便捷方法*/
+ (UIImage *)xw_imageWithSize:(CGSize)size drawBlock:(void (^)(CGContextRef context))drawBlock {
    if (!drawBlock) return nil;
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    if (!context) return nil;
    drawBlock(context);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

/**繪制方法的具體邏輯,遮罩圖片的邏輯是繪制一個矩形徊件,然后在繪制一個相應(yīng)的圓角矩形奸攻,然后填充矩形和圓角矩形的中間部分為父視圖的背景色*/
+ (UIImage *)xw_maskRoundCornerRadiusImageWithColor:(UIColor *)color cornerRadii:(CGSize)cornerRadii size:(CGSize)size corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth{
    return [UIImage xw_imageWithSize:size drawBlock:^(CGContextRef  _Nonnull context) {
        CGContextSetLineWidth(context, 0);
        [color set];
        CGRect rect = CGRectMake(0, 0, size.width, size.height);
        //繪制一個矩形蒜危,這里發(fā)-0.3是為了防止邊緣的鋸齒,
        UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:CGRectInset(rect, -0.3, -0.3)];
        //繪制圓角矩形睹耐,這里的0.3是為了防止內(nèi)邊框的鋸齒
        UIBezierPath *roundPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, 0.3, 0.3) byRoundingCorners:corners cornerRadii:cornerRadii];
        [rectPath appendPath:roundPath];
        CGContextAddPath(context, rectPath.CGPath);
        //注意要用EOFill方式進(jìn)行填充而非Fill方式
        CGContextEOFillPath(context);
        //如下是繪制邊框辐赞,原理依舊是繪制一個外邊框然后根據(jù)邊框?qū)挾壤L制一個內(nèi)邊框同樣采取EOFill的方式進(jìn)行填充即可
        if (!borderColor || !borderWidth) return;
        [borderColor set];
        UIBezierPath *borderOutterPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:cornerRadii];
        UIBezierPath *borderInnerPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:cornerRadii];
        [borderOutterPath appendPath:borderInnerPath];
        CGContextAddPath(context, borderOutterPath.CGPath);
        CGContextEOFillPath(context);
    }];
}

@end

上述的繪制方法充分利用了系統(tǒng)繪制圓角的方法bezierPathWithRoundedRect + EOFill,其實(shí)最開始我是考慮自己繪制四分之一的圓弧來構(gòu)建圓角的,后來發(fā)現(xiàn)不但代碼多了不少硝训,而且繪制出來的圓角始終沒有系統(tǒng)這個繪制方法的圓潤响委,我打印的系統(tǒng)的圓角路徑,發(fā)現(xiàn)其應(yīng)該不是四分之一圓弧窖梁,發(fā)現(xiàn)他的控制點(diǎn)取值有些奇怪赘风,我也不太清楚是如何取的,但是效果的確要好一點(diǎn)纵刘,總之采取如上的EOFill方式取巧邀窃,繪制的圓角圖片可以達(dá)到和系統(tǒng)的cornerRadius完全相同的效果!

2彰导、對于繪制的圖片蛔翅,我們應(yīng)該進(jìn)行保存,當(dāng)遇到顏色位谋,圓角以及邊框等屬性完全相同的繪制請求時候山析,我們可以及時復(fù)用,避免多次創(chuàng)建

優(yōu)缺點(diǎn)

優(yōu)點(diǎn)的話掏父,主要是避免了去解決上面說道提到的幾個問題笋轨,如果你有遇到上面3個問題的困擾,我覺得這是相當(dāng)不錯的方案

再羅列缺點(diǎn):

1赊淑、由于創(chuàng)建圖片需要一個背景色爵政,該背景色源于需要遮蓋視圖的父視圖的顏色,如果該父視圖的顏色不是純色或者存在透明的話陶缺,此時該方式就不適用了钾挟,此時還是應(yīng)該采取處理圖片的方式來解決;

2饱岸、如果父視圖的顏色會變化掺出,比如點(diǎn)擊cell的時候,此刻你需要同時更新遮罩圖片為相應(yīng)顏色的圖片苫费,所以需要多寫一些代碼汤锨。

封裝

對于此方案,我封裝了一個簡單的UIView的分類UIView+XWAddForRoundedCorner來達(dá)到目的百框,github地址是XWCornerRadius 闲礼,此分類分成簡單只有3個API ,且代碼只有200行,沒有其它依賴柬泽,具體API如下:


/**
 設(shè)置一個四角圓角

 @param radius 圓角半徑
 @param color  圓角背景色
 */
- (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color;

/**
 設(shè)置一個普通圓角

 @param radius  圓角半徑
 @param color   圓角背景色
 @param corners 圓角位置
 */
- (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners;

/**
 設(shè)置一個帶邊框的圓角

 @param cornerRadii 圓角半徑cornerRadii
 @param color       圓角背景色
 @param corners     圓角位置
 @param borderColor 邊框顏色
 @param borderWidth 邊框線寬
 */
- (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;

你只需要調(diào)用相應(yīng)的API就能完成一個圓角 + 邊框的遮罩效果慎菲,相同遮罩圖片的復(fù)用我也做了相關(guān)處理了,具體使用如下:

 [headerView xw_roundedCornerWithCornerRadii:XWSizeMake(40, 40) cornerColor:[UIColor whiteColor] corners:UIRectCornerAllCorners borderColor:[UIColor redColor] borderWidth:widthRatio(2)];

工程的demo中包含一個如下的列表(該截圖來自很老的ipod)聂抢,演示了具體的使用方法钧嘶,請自行查看:

demo列表.gif

寫在最后

對于此方法我已經(jīng)做了簡單的測試,性能還是相當(dāng)不錯的琳疏,雖然有圖層混合有决,但是相對于離屏渲染,都是小問題空盼,如上圖在我的老ipod的上也相當(dāng)流暢书幕,大家可以自行嘗試,更多的關(guān)于這幾種方案的性能比較揽趾,網(wǎng)上也已經(jīng)很多了台汇,大家可以自行查找,當(dāng)然你也可以使用YYWebImage來處理圖片的尺寸來進(jìn)一步優(yōu)化圖片的展示篱瞎, 如果在某些非常復(fù)雜的場景想要進(jìn)一步提高流暢度帮哈,YYKit的源碼以及 YY大神關(guān)于性能的相關(guān)文章絕對值得反復(fù)閱讀舟肉,不過對于優(yōu)化的態(tài)度蜂厅,我覺得還是先考慮需求的實(shí)現(xiàn)粮揉,再來考慮性能優(yōu)化最好,所謂過早的性能優(yōu)化都是魔鬼嘛~~~對于該圓角思路如果有疑問歡迎提出澄者,如果覺得有幫助笆呆,感謝star,再復(fù)習(xí)一遍github地址:XWCornerRadius

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粱挡,一起剝皮案震驚了整個濱河市赠幕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌询筏,老刑警劉巖榕堰,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嫌套,居然都是意外死亡局冰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門灌危,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碳胳,你說我怎么就攤上這事勇蝙。” “怎么了挨约?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵味混,是天一觀的道長产雹。 經(jīng)常有香客問我,道長翁锡,這世上最難降的妖魔是什么蔓挖? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮馆衔,結(jié)果婚禮上瘟判,老公的妹妹穿的比我還像新娘。我一直安慰自己角溃,他們只是感情好拷获,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著减细,像睡著了一般匆瓜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上未蝌,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天驮吱,我揣著相機(jī)與錄音,去河邊找鬼萧吠。 笑死左冬,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怎憋。 我是一名探鬼主播又碌,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绊袋!你這毒婦竟也來了毕匀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤癌别,失蹤者是張志新(化名)和其女友劉穎皂岔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體展姐,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躁垛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了圾笨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片教馆。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖擂达,靈堂內(nèi)的尸體忽然破棺而出土铺,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布悲敷,位于F島的核電站究恤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏后德。R本人自食惡果不足惜部宿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瓢湃。 院中可真熱鬧理张,春花似錦、人聲如沸箱季。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藏雏。三九已至拷况,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掘殴,已是汗流浹背赚瘦。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奏寨,地道東北人起意。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像病瞳,于是被迫代替她去往敵國和親揽咕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,527評論 25 707
  • 轉(zhuǎn)載:http://www.reibang.com/p/32fcadd12108 每個UIView有一個伙伴稱為l...
    F麥子閱讀 6,157評論 0 13
  • 久未作詩書套菜,忘罷筆耕讀亲善。 青絲未成雪,黃雞唱夢圖逗柴。 身似千般重蛹头,人行旅窮途。 不堪風(fēng)霜月戏溺,怨天恨氣抒渣蜗。 可笑江郎筆...
    糊涂印象閱讀 180評論 -1 1
  • 人們都說人死后會變成一顆星星耕拷,今天天氣很好晚上卻不見一顆星星。我想知道大伯去了哪里托享,是藏在云里了嗎骚烧? 2月19日控淡,...
    沫殤渝閱讀 350評論 4 2
  • 1.做活動 2.發(fā)單 3.技能訓(xùn)練 4.口才訓(xùn)練
    快樂番茄閱讀 116評論 0 0