這篇文章,要解決的是,使用一個自定義的 imageNamed 函數來替代系統的 imageNamed 函數.內部邏輯,將貫穿對比論證 關於"合適"的圖片的定義.對iOS加載圖片的規則不是很熟悉的童鞋,能夠着重看這篇.react
iPhone 7 plus(iOS10.0): sample@3x.png > sample@2x.png > sample~iphone.png >sample.png 其餘後綴的圖片老是不被加載.ios
iPad Pro 12.9 inch(iOS10.0): sample@2x.png > sample~ipad.png > sample.png 其餘後綴的圖片老是不被加載.git
不一樣後綴的圖片 | iPhone 7 plus(iOS10.0) | iPad Pro 12.9 inch(iOS10.0) |
---|---|---|
sample.png | 7 | 8 |
sample@2x.png | 9 | 10 |
sample@3x.png | 10 | 0 |
sample~iphone.png | 8 | 0 |
sample~iphone@2x.png | 0 | 0 |
sample~iphone@3x.png | 0 | 0 |
sample~ipad.png | 0 | 9 |
sample~ipad@2x.png | 0 | 0 |
可使用同名不一樣內容的圖片來對比觀察.優先級從高到低.優先級較高的優先被加載,優先級爲0的永遠不會被加載.僅以iPhone 7 plus 和 iPad Pro爲例分析,其餘狀況可自行.所用驗證版本爲iOS10,將來不一樣機型手機和系統可能會有差別.github
想本身動手試一下的,能夠下載示例: https://github.com/ios122/ios_assets_hot_update/raw/master/res/ios_assets_hot_update_2.zip 很小,只有100多K.編譯,我此時用的是 Xcode 8.react-native
資源把到一個bundle包中,便於保留資源的目錄結構,也方便總體管理與替換.iOS中的bundle包,就一個一個特殊的以.bunle結尾的文件夾.示例中,我使用的是main.bundle.另外,關於bundle保留資源目錄結構這個特色,是react-native中很依賴的一個特性,之後你的項目中或許也會須要.若是單單只是從原有 Images.xcassets 遷移代碼的話,此處都放於同一層級便可.iphone
把圖片放到資源文件夾main.bundle後,再加載圖片,能夠參考下面的代碼,這樣作的額外的好處就是能夠適當減少圖片加載的內存佔用問題:函數
NSString * bundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:@"main.bundle"]; NSBundle * mainBundle = [NSBundle bundleWithPath:bundlePath]; NSString * imgPath = [mainBundle pathForResource:@"sample" ofType:@"png"]; self.sampleImageView.image = [UIImage imageWithContentsOfFile: imgPath];
首先是須要顯示加載 @3x 的圖片:url
NSString * imgPath = [mainBundle pathForResource:@"sample@3x" ofType:@"png"];
此時代碼,在iPhone 7 / iPhone 7 plus/ iPad Pro,都能顯示圖片,直接輸出圖片自己的尺寸都爲 原圖尺寸的 1/3.3d
NSLog(@"加載後的圖片尺寸:%@",[NSValue valueWithCGSize:self.sampleImageView.image.size]);
可是,此處有一個問題.@3x老是被解讀爲三倍圖,在iPhone上,正是咱們須要的尺寸,可是在iPad上,尺寸就有些偏小了.咱們在iPad上,一般老是須要將此張圖按照@2x圖來顯示.這是一個規律!作過iPhone和iPad通用圖標尺寸適配的童鞋,應該早就注意到了.code
因此,如今要解決的關鍵技術問題是:如何把 @3x圖,在iPad上按照@2x圖來解讀?相對完整代碼以下,最終輸出的圖片尺寸在iPhone上爲原始尺寸的1/3,在iPad上爲原始尺寸的1/2,正是咱們須要的:
NSString * bundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:@"main.bundle"]; NSBundle * mainBundle = [NSBundle bundleWithPath:bundlePath]; NSString * imgPath = [mainBundle pathForResource:@"sample@3x" ofType:@"png"]; UIImage * image; static NSString * model; if (!model) { model = [[UIDevice currentDevice]model]; } if ([model isEqualToString:@"iPad"]) { NSData *imageData = [NSData dataWithContentsOfFile: imgPath]; image = [UIImage imageWithData:imageData scale:2.0]; }else{ image = [UIImage imageWithContentsOfFile: imgPath]; } self.sampleImageView.image = image; NSLog(@"加載後的圖片尺寸:%@",[NSValue valueWithCGSize:self.sampleImageView.image.size]);
此處實現了一個簡單夠用的類目方法,支持從指定bundle讀取指定名字的圖片:
#import "UIImage+imageNamed_bundle_.h" @implementation UIImage (imageNamed_bundle_) + (UIImage *)imageNamed:(NSString *)imgName bundle:(NSString *)bundleName { bundleName = [NSString stringWithFormat:@"%@.bundle",bundleName]; imgName = [NSString stringWithFormat:@"%@@3x",imgName]; NSString * bundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent: bundleName]; NSBundle * mainBundle = [NSBundle bundleWithPath:bundlePath]; NSString * imgPath = [mainBundle pathForResource:imgName ofType:@"png"]; UIImage * image; static NSString * model; if (!model) { model = [[UIDevice currentDevice]model]; } if ([model isEqualToString:@"iPad"]) { NSData *imageData = [NSData dataWithContentsOfFile: imgPath]; image = [UIImage imageWithData:imageData scale:2.0]; }else{ image = [UIImage imageWithContentsOfFile: imgPath]; } return image; } @end
藉助類目,原來的調用,能夠簡化爲:
UIImage * image = [UIImage imageNamed:@"sample" bundle:@"main"]; self.sampleImageView.image = image;
也支持有層級結構的圖片資源的讀取呦:
UIImage * image = [UIImage imageNamed:@"sub/sample" bundle:@"main"]; self.sampleImageView.image = image;
http://stackoverflow.com/questions/4976005/image-from-url-for-retina-display
http://stackoverflow.com/questions/11197509/ios-how-to-get-device-make-and-model