如何高性能的給 UIImageView 加圓角

肯定不是使用cornerRadius!!! 否則這題目不是顯得很弱智。本文會先講為什么不能這么做,再講應(yīng)該如何做

為什么不能使用 cornerRadius

注意審題,題目說的是高性能。那么我們首先要知道使用 cornerRadius 為何會使得性能下降。
首先說一下 GPU 的兩種渲染方式,當(dāng)前屏幕渲染離屏渲染

  • On-Screen Rendering
    意為當(dāng)前屏幕渲染,指的是GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行。

  • Off-Screen Rendering
    意為離屏渲染,指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開辟一個(gè)緩沖區(qū)進(jìn)行渲染操作。

再來看代碼:

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

如上面代碼,直接使用 cornerRadius 對 imageView 設(shè)置圓角,其渲染方式為 GPU 離屏渲染。而相比于當(dāng)前屏幕渲染,離屏渲染的代價(jià)是很高的,主要體現(xiàn)在兩個(gè)方面:

1.創(chuàng)建新緩沖區(qū)

要想進(jìn)行離屏渲染,首先要?jiǎng)?chuàng)建一個(gè)新的緩沖區(qū)。

2.上下文切換

離屏渲染的整個(gè)過程,需要多次切換上下文環(huán)境:先是從當(dāng)前屏幕(On-Screen)切換到離屏(Off-Screen),等到離屏渲染結(jié)束以后,將離屏緩沖區(qū)的渲染結(jié)果顯示到屏幕上有需要將上下文環(huán)境從離屏切換到當(dāng)前屏幕。而上下文環(huán)境的切換是要付出很大代價(jià)的。

會觸發(fā)離屏渲染的操作還有很多,想了解可以自行谷歌或百度

請注意:并非不能使用 cornerRadius 來加圓角,只是如果當(dāng)前屏幕中這樣的圓角操作達(dá)到一定數(shù)量,會觸發(fā)緩沖區(qū)的頻繁合并和上下文的的頻繁切換,性能的代價(jià)會宏觀地表現(xiàn)在用戶體驗(yàn)上----掉幀。


應(yīng)該如何高性能的給 UIImageView 加圓角

正確的做法是切換到工作線程利用CoreGraphic API生成一個(gè)Off-Screen UIImage,再切換到main thread賦值給UIImageView。
不多 BB, 直接貼代碼:

-(void)cxb_cornerRadiusWithImage:(UIImage *)image cornerRadius:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType { 
    CGSize size = self.bounds.size; 
    CGFloat scale = [UIScreen mainScreen].scale; 
    CGSize cornerRadiu = CGSizeMake(cornerRadius, cornerRadius);     
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        UIGraphicsBeginImageContextWithOptions(size, YES, scale); 
        if (nil == UIGraphicsGetCurrentContext()) { 
            return; 
        } 
        UIBezierPath *cornerPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:rectCornerType cornerRadiu:cornerRadiu]; 
        [cornerPath addClip]; 
        [image drawInRect:self.bounds]; 
        id processedImageRef = (__bridge id _Nullable)(UIGraphicsGetImageFromCurrentImageContext().CGImage); 
        UIGraphicsEndImageContext(); 
        dispatch_async(dispatch_get_main_queue(), ^{ 
            self.layer.contents = processedImageRef; 
        }); 
    });
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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