當(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];
![](https://github.com/raozhizhen/JMRoundedCorner/blob/master/JMRoundedCornerGIF.gif?raw=true)
聯(lián)系我
- QQ:337519524
- 郵箱:raozhizhen@gmail.com
感謝
性能上的優(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