iOS開發之0行代碼載入NSBundle中的@2x與@3x圖片

來源:互聯網
上載者:User

標籤:ios   nsbundle   pathforresource   

    本文只針對通過NSBundle對象的方法 pathForResource 擷取本地圖片資源遇到的圖片名無法自動識別@2x與@3x名稱的問題進行測試、總結與分享。


    載入本地圖片資源的方式一般通過以下兩種方法:

第1種:

    UIImage *img = [UIImage imageNamed:@"imageName"];

第2種:

    UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"imageName" ofType:@"imageType"]];


註:其他方法如NSData等本文不涉及,如需瞭解請找某哥或某娘,謝謝合用。

    

    假定我們都知道第1種方法適合讀取重複使用且佔用記憶體小的圖片資源,且能根據當前手機硬體能th自動識別“@2x”圖或“@3x”圖。但如果需要載入不常使用且佔用記憶體很大如上百kb甚至上M的圖片資源的時候還使用這方式,記憶體佔用勢必會很嚴重。解決這種載入圖片資源佔用記憶體問題首選方案是換到第2種,但傳入的資源名必須與“.尾碼名”前的名稱一致,如果資源名添加了“@2x”或“@3x”,而傳入的resource名稱帶或不帶“@2x”或“@3x”標識,結果分別會是怎麼樣的呢?下面我們來測試一下。

> 不帶“@2x”或“@3x”標識:

650) this.width=650;" src="https://s1.51cto.com/oss/201711/16/8b57e24dc94791653df6e98dc81544e4.png" title="img1.png" alt="8b57e24dc94791653df6e98dc81544e4.png" />


> 帶“@2x”或“@3x”標識


650) this.width=650;" src="https://s1.51cto.com/oss/201711/16/d542ba5a5a99c1993c61a676ee9f4640.png" title="img2.png" alt="d542ba5a5a99c1993c61a676ee9f4640.png" />

    顯然傳入的名稱帶標識後能正常擷取到圖片資源。


    但現在我就是想能過第2種方法載入本地圖片資源能像第1種方法一樣,不需要傳入帶“@2x”和“@3x”的標識就能正常讀取到圖片資源,我們要怎麼處理呢?

    方法1:在每處都對當前裝置進行判斷,並保證輸入的檔案名稱正確,即Bundle裡存在帶或不帶標識的資源圖片檔案。

    if(是@3x圖裝置) {        讀取@3x資源圖片路徑;    }    else if (是@2x圖裝置) {        讀取@2x資源圖片路徑;    }    else {        讀取不帶@2x和@3x資源圖片路徑;    }

但是請問有誰會願意如上述方法在每個地方作這個判斷呢?


方法2:給NSBundle添加Category,輸入帶或不帶標識,自動識別對應資源圖片檔案。

這種方法其實是對方法1的封裝,思路同方法1,但略有完善。

邏輯如下:

    if(是@3x圖裝置) {        讀取@3x圖路徑;        if(不存在@3x圖){           讀取@2x資源圖片;           if(不存在@2x圖){               讀取不帶@2x和@3x資源圖片;           }        }    }    else if (是@2x圖裝置) {        讀取@2x圖路徑;        if(不存在@2x圖){           讀取@3x資源圖片;           if(不存在@3x圖){               讀取不帶@2x和@3x資源圖片;           }        }    }    else {        讀取不帶@2x和@3x資源圖片;        if(不存在@1x圖){           讀取@2x資源圖片;           if(不存在@2x圖){               讀取@3x資源圖片;           }        }    }


代碼實現如下:

    運用Runtime知識,在類方法 load 裡作方法替換:

+ (void)load {    Method originMethod = class_getInstanceMethod(self, @selector(pathForResource:ofType:));    Method newMethod = class_getInstanceMethod(self, @selector(tempPathForResource:ofType:));    method_exchangeImplementations(originMethod, newMethod);}


替換的方法為:

- (NSString *)tempPathForResource:(NSString *)name ofType:(NSString *)ext {    NSString *path = [self tempPathForResource:name ofType:ext];    if (path) {        return path;    }    CGFloat scale = [UIScreen mainScreen].scale;    if (ABS(scale-3) <= 0.001) {        path = [self tempPathForResource_3x:name ofType:ext];        if (!path) {            path = [self tempPathForResource_2x:name ofType:ext];            if (!path) {                path = [self tempPathForResource_x:name ofType:ext];            }        }            }    else if (ABS(scale-2) <= 0.001){        path = [self tempPathForResource_2x:name ofType:ext];        if (!path) {            path = [self tempPathForResource_3x:name ofType:ext];            if (!path) {                path = [self tempPathForResource_x:name ofType:ext];            }        }    }    else {        path = [self tempPathForResource_x:name ofType:ext];        if (!path) {            path = [self tempPathForResource_2x:name ofType:ext];            if (!path) {                path = [self tempPathForResource_3x:name ofType:ext];            }        }    }        return path;}


    在這個方法裡,優先使用原生系統的方法,如果資源能找到即返回了資源圖片的path,則直接返回;否則進入下面的尋找流程。在每一次尋找結束後均進行判斷,如果尋找成功跳出if判斷並返回尋找到的path,否則進入下一種裝置的尋找。其中,尋找@2x圖還是@3x圖,通過下面這個值判斷的:

    CGFloat scale = [UIScreen mainScreen].scale;

    在使用變數 scale 進行判斷的時候,使用的是“ABS(差) <= 0.001”方式,因為UIScreen對象的屬性“scale”是一個CGFloat類型的值:

650) this.width=650;" src="https://s3.51cto.com/oss/201711/16/50e7f8c3ae909cb8ca819e828f3c41ea.png" title="img3.png" alt="50e7f8c3ae909cb8ca819e828f3c41ea.png" />


    在尋找資源圖片的時候有這麼一個問題,如果當前裝置是@3x的裝置,如iPhone6 Plus 或 iPhone7 Plus 或其它需要@3x圖資源的裝置,但我們添加進來的是@2x圖資源或@1x圖資源,即這正是本文要解決的問題。

    針對倍率不同的裝置,處理的邏輯也是不一樣的。

>對@1x圖的裝置:

if(輸入的資源圖片名為@3x的){    把"@3x"去掉;}else if (輸入的資源圖片名為@2x的) {    把"@2x"去掉;}else {    不作處理;}調用原生系統方法讀取path;


>對@2x圖的裝置:

if(輸入的資源圖片名為@3x的){    把"@3x"替換為"@2x";}else if (輸入的資源圖片名為@2x的) {    不作處理;}else {    給資源圖片名加"@2x"尾碼;}調用原生系統方法讀取path;


>對@3x圖的裝置:

if(輸入的資源圖片名為@3x的){    不作處理;}else if (輸入的資源圖片名為@2x的) {    把"@2x"替換為"@3x";}else {    給資源圖片名加"@3x"尾碼;}調用原生系統方法讀取path;


以上三種邏輯的代碼分別如下:

>對@1x圖的裝置:

- (NSString *)tempPathForResource_x:(NSString *)name ofType:(NSString *)ext {    NSString *path = nil;    NSString *teampName = nil;        if ([name hasSuffix:@"@3x"]) {        teampName = [name stringByReplacingOccurrencesOfString:@"@3x" withString:@""];    }    else if ([name hasSuffix:@"@2x"]) {        teampName = [name stringByReplacingOccurrencesOfString:@"@2x" withString:@""];    }    else {        teampName = name;    }    path = [self tempPathForResource:teampName ofType:ext];        return path;}


>對@2x圖的裝置:

- (NSString *)tempPathForResource_2x:(NSString *)name ofType:(NSString *)ext {    NSString *path = nil;    NSString *teampName = nil;        if ([name hasSuffix:@"@3x"]) {        teampName = [name stringByReplacingOccurrencesOfString:@"@3x" withString:@"@2x"];    }    else if ([name hasSuffix:@"@2x"]) {        teampName = name;    }    else {        teampName = [NSString stringWithFormat:@"%@@2x", name];    }    path = [self tempPathForResource:teampName ofType:ext];        return path;}


>對@3x圖的裝置:

- (NSString *)tempPathForResource_3x:(NSString *)name ofType:(NSString *)ext {    NSString *path = nil;    NSString *teampName = nil;        if ([name hasSuffix:@"@3x"]) {        teampName = name;    }    else if ([name hasSuffix:@"@2x"]) {        teampName = [name stringByReplacingOccurrencesOfString:@"@2x" withString:@"@3x"];    }    else {        teampName = [NSString stringWithFormat:@"%@@3x", name];    }    path = [self tempPathForResource:teampName ofType:ext];        return path;}


通過上述處理後,測試結果如下:

650) this.width=650;" src="https://s3.51cto.com/oss/201711/16/08fe1f3e78e550907b380e7c857620e5.png" title="img4.png" alt="08fe1f3e78e550907b380e7c857620e5.png" />



本文原始碼見:

https://github.com/zhoushejun/iOSNotes/blob/master/SJNotes/Classes/UI/Utilities/Categories/NSBundle%2BResource



參考資料:

http://blog.csdn.net/null29/article/details/53640179

http://www.jianshu.com/p/f40313d37049


本文出自 “江山風雨” 部落格,請務必保留此出處http://965678322.blog.51cto.com/4935622/1982197

iOS開發之0行代碼載入NSBundle中的@2x與@3x圖片

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.