Swift高效設(shè)置圓角圖片的方法

App中圓角常用的場景有:UIImageView(頭像及cell中圖片)、Button按鈕(按鈕)、Label文字(文字)等等。這些控件的圓角設(shè)置原理都是一樣的,這里就以UIImageView圓角設(shè)置為例。
1.系統(tǒng)提供的圓角設(shè)置屬性:

 icon.layer.cornerRadius = 50
 icon.layer.masksToBounds = true

cornerRadius屬性本身并沒有什么問題,而masksToBounds屬性會(huì)造成離屏渲染從而影響性能。

ps:Offscreen rendering(離屏渲染):離屏渲染指的是在圖像在繪制到當(dāng)前屏幕前,需要先進(jìn)行一次渲染,之后才繪制到當(dāng)前屏幕。在第一次渲染時(shí),GPU(Core Animation)或CPU(Core Graphics)需要額外的一塊內(nèi)存來進(jìn)行渲染,完成后再繪制到屏幕。offscreen到onscreen需要進(jìn)行上下文切換,這個(gè)切換的性能消耗是昂貴的。

事實(shí)上,當(dāng)界面中單個(gè)或少量控件用此方法設(shè)置圓角,并不會(huì)影響性能,我們并不需要擔(dān)心,但如果界面中大量使用此方法設(shè)置圓角,比如TableView中顯示圓角圖片等,滾動(dòng)時(shí)就會(huì)出現(xiàn)界面卡頓,這當(dāng)然不是我們想要看到的。

2.為了不讓圖像離屏渲染:
可以自己繪制圓角:

 @objc private func testDrawCornerImage(){
    let startTime = CACurrentMediaTime()
    for _ in 0..<100 {
        let icon = UIImageView.init(frame: CGRect.init(x: 100, y: 400, width: 100, height: 100))
        icon.image = UIImage.init(named: "ic_icon")
        //1.建立上下文
        UIGraphicsBeginImageContextWithOptions(icon.bounds.size, true, 0)
        //獲取當(dāng)前上下文
        let ctx = UIGraphicsGetCurrentContext()
        
        //設(shè)置填充顏色
        UIColor.white.setFill()
        UIRectFill(icon.bounds)
        //2.添加圓及裁切
        let rect = CGRect.init(x: 0, y: 0, width: icon.bounds.size.width, height: icon.bounds.size.height)
        
        ctx?.addEllipse(in: rect)
        //裁切
        ctx?.clip()
        
        //3.繪制圖像
        icon.draw(icon.bounds)
        
        //4.獲取繪制的圖像
        icon.image = UIGraphicsGetImageFromCurrentImageContext()
        
        //5關(guān)閉上下文
        UIGraphicsEndImageContext()
        
        view.addSubview(icon)
    }
    print("方法三:testDrawCornerImage-->圓角設(shè)置消耗時(shí)間\(CACurrentMediaTime() - startTime)")
}

//也可以直接用貝塞爾設(shè)置圓形路徑進(jìn)行繪制

@objc private func testDrawWithBezierPath(){
    let startTime = CACurrentMediaTime()
    for _ in 0..<100 {
    let icon = UIImageView.init(frame: CGRect.init(x: 100, y: 250, width: 100, height: 100))
    icon.image = UIImage.init(named: "ic_icon")
    //1.建立上下文
    UIGraphicsBeginImageContextWithOptions(icon.bounds.size, true, 0)
    
    //設(shè)置填充顏色
    UIColor.white.setFill()
    UIRectFill(icon.bounds)
    
    //2.創(chuàng)建橢圓path,寬、高一致返回的就是圓形路徑
    let path = UIBezierPath.init(ovalIn: icon.bounds)
    
    //也可以這樣:
    // let path2 = UIBezierPath.init(roundedRect: icon.bounds, cornerRadius: icon.bounds.size.width*0.5)
    //裁切
    path.addClip()
    //3.繪制圖像
    icon.draw(icon.bounds)
    
    //4.獲取繪制的圖像
    icon.image = UIGraphicsGetImageFromCurrentImageContext()
    
    //5關(guān)閉上下文
    UIGraphicsEndImageContext()
    
    view.addSubview(icon)
    }
    print("方法二:testDrawWithBezierPath-->圓角設(shè)置消耗時(shí)間\(CACurrentMediaTime() - startTime)")
}

對(duì)上面兩個(gè)繪制圓角的方法性能進(jìn)行了簡單的測試,分別進(jìn)行多輪的100次測試,時(shí)間消耗上差別基本無幾,大家可以選擇任何一種方法使用。

ps: UIGraphicsBeginImageContextWithOptions方法參數(shù)說明:
size —- 圖形上下文的大小
opaque —- 透明開關(guān),如果圖形完全不用透明,設(shè)置為YES以優(yōu)化位圖的存儲(chǔ)。
scale —– 縮放因子,可以用[UIScreen mainScreen].scale來獲取,但實(shí)際上設(shè)為0后,系統(tǒng)就會(huì)自動(dòng)設(shè)置正確的比例了。在Retina屏幕上最好不要自己手動(dòng)設(shè)置他的縮放比例,直接設(shè)置0,系統(tǒng)就會(huì)自動(dòng)進(jìn)行最佳的縮放

關(guān)鍵在于:繪制圓角最好在子線程進(jìn)行,這樣不會(huì)阻塞主線程,用戶體驗(yàn)上會(huì)更好,特別是對(duì)于UITableView列表這樣的場景,異步繪制是必須的,不然UITableView滑動(dòng)可能會(huì)出現(xiàn)卡頓的情況。

可以將設(shè)置圓角方法放在UIImageView+Extension.swift(Swift在3.0以后沒有Category,Extension文件之分了)文件中,創(chuàng)建setCornerImage方法:

import Foundation
import UIKit
extension UIImageView{

func setCornerImage(){
    //異步繪制圖像
    DispatchQueue.global().async(execute: {
        //1.建立上下文
    
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0)

        //獲取當(dāng)前上下文
        let ctx = UIGraphicsGetCurrentContext()
        
        //設(shè)置填充顏色
        UIColor.white.setFill()
        UIRectFill(self.bounds)
        
        //2.添加圓及裁切
        ctx?.addEllipse(in: self.bounds)
        //裁切
        ctx?.clip()
        
        //3.繪制圖像
        self.draw(self.bounds)
        
        //4.獲取繪制的圖像
        let image = UIGraphicsGetImageFromCurrentImageContext()
        
        //5關(guān)閉上下文
        UIGraphicsEndImageContext()
        
        DispatchQueue.main.async(execute: {
            self.image = image
        })
    })
}}

在需要設(shè)置圓角的地方直接調(diào)用即可,例如:

    let icon = UIImageView.init(frame: CGRect.init(x: 10, y: 10, 
    width: 50, height: 50))
    icon.image = UIImage.init(named: "ic_icon")
    icon.setCornerImage()
    addSubview(icon)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,041評(píng)論 4 61
  • (1)Time Profiler:用來測量被方法/函數(shù)打斷的CPU使用情況。 (2)Core Animation:...
    錢噓噓閱讀 1,759評(píng)論 2 6
  • 早上好!#幸福實(shí)修#~每天進(jìn)步1%#幸福實(shí)修10班-16號(hào)@駱金芳--富陽# 20170824(31/60) 【幸...
    幸福實(shí)修金芳閱讀 283評(píng)論 2 0
  • 冬日行走在許電里, 思緒如漂浮的白云,自由飄逸,奔放無羈! 又是新的一天,晨霧漸漸退去,初升的太陽使大地變得逐漸明...
    久稞閱讀 297評(píng)論 0 0
  • 有些情緒是說給聽的懂得人聽
    J灰塵閱讀 168評(píng)論 0 0

友情鏈接更多精彩內(nèi)容