每日一問06——imageView的圓角優(yōu)化

基本方法

使用layer的cornerRadius屬性和masksToBounds刃泡。

self.imageView.layer.cornerRadius = 8.f;
self.imageView.layer.masksToBounds = YES;

這樣設(shè)置圓角是最基本的一種方式,但當(dāng)屏幕中有多個圓角圖片存在會發(fā)生明顯的界面卡頓現(xiàn)象闺金。
原因是cornerRadius和masksToBounds同時(shí)使用會發(fā)生離屏渲染(離屏渲染參考每日一問03
值得一提的是iOS9以后逾滥,cornerRadius = YES在UIImageView上不會發(fā)生離屏渲染,但在button等其他控件上使用還是會發(fā)生败匹。

這種方法使用場景就是同界面中沒有過多的圓角圖片寨昙。

基本方案的優(yōu)化

setCornerRadius設(shè)置圓角之后,shouldRasterize=YES光柵化
原理是開啟了光柵化以后掀亩,可以使離屏渲染的結(jié)果緩存到內(nèi)存中存為位圖舔哪, 使用的時(shí)候直接使用緩存,節(jié)省了一直離屏渲染損耗的性能槽棍。
問題:
1.被光柵化的圖片如果超過100ms沒有被使用,則會被移除
2.系統(tǒng)限制了緩存的大小為2.5X Screen Size.如果過度使用,超出緩存之后,同樣會造成大量的offscreen渲染

所以如果不是同一張圖片多次使用捉蚤,這種方案也不可取。

使用 mask layer

UIBezierPath* maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];
    
    CAShapeLayer* maskLayer = [CAShapeLayer layer];
    maskLayer.frame = imageView.bounds;
    maskLayer.path = maskPath.CGPath;
    
    imageView.layer.mask = maskLayer;

這種方法本質(zhì)上是用遮罩層 mask 來實(shí)現(xiàn)炼七,因此同樣無可避免的會導(dǎo)致離屏渲染缆巧。

使用混合圖層

在要添加圓角的視圖上再疊加一個部分透明的視圖,只對圓角部分進(jìn)行遮擋豌拙。多一個圖層會增加合成的工作量盅蝗,但這點(diǎn)工作量與離屏渲染相比微不足道,性能上無論各方面都和無效果持平姆蘸。

透明圖片

這種方式在性能上非常的好墩莫,但是缺點(diǎn)就是角度不同需要設(shè)計(jì)師提供多張不同的圖片,非常不靈活逞敷。

image.png

直接裁剪image

實(shí)現(xiàn)一狂秦,這個方案的思路是將離屏渲染的消耗從GPU轉(zhuǎn)交給CPU,讓CPU提前處理一下bitmap數(shù)據(jù)推捐。這算是CPU的離屏渲染裂问。

CGRect rect = CGRectMake(0, 0, size.width, size.height);
    
    UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radius, radius)];
    CGContextAddPath(ctx,path.CGPath);
    CGContextClip(ctx);
    [self drawInRect:rect];
    CGContextDrawPath(ctx, kCGPathFillStroke);
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;

實(shí)現(xiàn)二,這個方案采用SDWebImage處理圖片時(shí)Core Graphics繪制圓角。

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth,
                                 float ovalHeight)
{
    float fw, fh;
    
    if (ovalWidth == 0 || ovalHeight == 0)
    {
        CGContextAddRect(context, rect);
        return;
    }
    
    CGContextSaveGState(context);
    CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM(context, ovalWidth, ovalHeight);
    fw = CGRectGetWidth(rect) / ovalWidth;
    fh = CGRectGetHeight(rect) / ovalHeight;
    
    CGContextMoveToPoint(context, fw, fh/2);  // Start at lower right corner
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);  // Top right corner
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); // Top left corner
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); // Lower left corner
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); // Back to lower right
    
    CGContextClosePath(context);
    CGContextRestoreGState(context);
}

- (UIImage *)createImageWith:(CGSize)imageSize Radius:(CGFloat)radius{
    int w = imageSize.width;
    int h = imageSize.height;
    UIImage *img = self;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
    CGRect rect = CGRectMake(0, 0, w, h);
    CGContextBeginPath(context);
    addRoundedRectToPath(context, rect, radius, radius);
    CGContextClosePath(context); CGContextClip(context);
    CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    img = [UIImage imageWithCGImage:imageMasked];
    CGContextRelease(context); CGColorSpaceRelease(colorSpace); CGImageRelease(imageMasked);
    
    return img;
}

同樣沒有離屏渲染但這個方案在性能上比方案一更好堪簿,主要體現(xiàn)在CPU和內(nèi)存消耗更低痊乾。從實(shí)現(xiàn)上來分析,方案二的優(yōu)點(diǎn)主要是采用了強(qiáng)制解壓生成位圖椭更。優(yōu)化了CPU進(jìn)行解壓那一塊的消耗哪审。(參考每日一問04

總結(jié):圓角優(yōu)化這個話題雖然已經(jīng)過去很久,網(wǎng)上也給出了很多成熟的解決方案虑瀑,但導(dǎo)致需要優(yōu)化的原理和優(yōu)化方案的原理我們還是應(yīng)該了解的湿滓。

相關(guān)文章

iOS 高效添加圓角效果實(shí)戰(zhàn)講解
iOS 高效添加圓角效果實(shí)戰(zhàn)講解-簡書
圓角卡頓刨根問底
iOS圖片高性能設(shè)置圓角
iOS UIView 圓角和加邊框方式總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市舌狗,隨后出現(xiàn)的幾起案子叽奥,更是在濱河造成了極大的恐慌,老刑警劉巖痛侍,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件朝氓,死亡現(xiàn)場離奇詭異,居然都是意外死亡主届,警方通過查閱死者的電腦和手機(jī)赵哲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岂膳,“玉大人誓竿,你說我怎么就攤上這事磅网√附兀” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵涧偷,是天一觀的道長簸喂。 經(jīng)常有香客問我,道長燎潮,這世上最難降的妖魔是什么喻鳄? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮确封,結(jié)果婚禮上除呵,老公的妹妹穿的比我還像新娘。我一直安慰自己爪喘,他們只是感情好颜曾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秉剑,像睡著了一般泛豪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天诡曙,我揣著相機(jī)與錄音臀叙,去河邊找鬼。 笑死价卤,一個胖子當(dāng)著我的面吹牛劝萤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荠雕,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼稳其,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了炸卑?” 一聲冷哼從身側(cè)響起既鞠,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤盖文,失蹤者是張志新(化名)和其女友劉穎五续,沒想到半個月后疙驾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體它碎,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年傻挂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挖息。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖幢码,靈堂內(nèi)的尸體忽然破棺而出蛤育,到底是詐尸還是另有隱情瓦糕,我是刑警寧澤咕娄,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布亥揖,位于F島的核電站圣勒,受9級特大地震影響圣贸,放射性物質(zhì)發(fā)生泄漏滑负。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一痴鳄、第九天 我趴在偏房一處隱蔽的房頂上張望缸夹。 院中可真熱鬧槽华,春花似錦披摄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背读串。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撒妈,地道東北人恢暖。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像狰右,于是被迫代替她去往敵國和親杰捂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348

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