实现iOS图片等资源文件的热更新化(二):自定义的动态 imageNamed
这篇文章,要解决的是,使用一个自定义的 imageNamed 函数来替代系统的 imageNamed 函数.内部逻辑,将贯穿对比论证 关于"合适"的图片的定义.对iOS加载图片的规则不是很熟悉的童鞋,可以着重看这篇.
不同后缀图片加载的优先级
iPhone 7 plus(iOS10.0): sample@3x.png > sample@2x.png > sample~iphone.png >sample.png
其他后缀的图片总是不被加载.iPad Pro 12.9 inch(iOS10.0): sample@2x.png > sample~ipad.png > sample.png 其他后缀的图片总是不被加载.
不同后缀的图片 | 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,未来不同机型手机和系统可能会有差异.
想自己动手试一下的,可以下载示例: https://github.com/ios122/ios_assets_hot_update/raw/master/res/ios_assets_hot_update_2.zip 很小,只有100多K.编译,我此时用的是 Xcode 8.
使用bundle包放置图片等资源文件
资源把到一个bundle包中,便于保留资源的目录结构,也方便整体管理与替换.iOS中的bundle包,就一个一个特殊的以.bunle结尾的文件夹.示例中,我使用的是main.bundle.另外,关于bundle保留资源目录结构这个特点,是react-native中很依赖的一个特性,以后你的项目中或许也会需要.如果单单只是从原有 Images.xcassets 迁移代码的话,此处都放于同一层级即可.
使用 imageWithContentsOfFile: 加载图片
把图片放到资源文件夹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];
使iPhone @3x 与iPad @2x 共用同一张图片
首先是需要显示加载 @3x 的图片:
NSString * imgPath = [mainBundle pathForResource:@"sample@3x" ofType:@"png"];
此时代码,在iPhone 7 / iPhone 7 plus/ iPad Pro,都能显示图片,直接输出图片本身的尺寸都为 原图尺寸的 1/3.
NSLog(@"加载后的图片尺寸:%@",[NSValue valueWithCGSize:self.sampleImageView.image.size]);
但是,此处有一个问题.@3x总是被解读为三倍图,在iPhone上,正是我们需要的尺寸,但是在iPad上,尺寸就有些偏小了.我们在iPad上,通常总是需要将此张图按照@2x图来显示.这是一个规律!做过iPhone和iPad通用图标尺寸适配的童鞋,应该早就注意到了.
所以,现在要解决的关键技术问题是:如何把 @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]);
封装为类目(category),实现自定义的 imageNamed
此处实现了一个简单够用的类目方法,支持从指定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
系列专属 github 项目主页
https://github.com/ios122/ios_assets_hot_update
实现iOS图片等资源文件的热更新化(二):自定义的动态 imageNamed相关推荐
- 前嗅ForeSpider教程:采集图片/视频/资源文件的链接地址
昨天为大家介绍了如何采集图片/视频/资源文件后,有小伙伴问我如何采集他们的链接地址,今天小编就为大家演示如何采集图片/视频/资源文件的链接地址,操作如下: 第一步:新建任务 ①点击左上角"加 ...
- android jar 加入图片,Android动态加载外部jar包及jar包中图片等资源文件
Android动态加载外部jar包及jar包中图片等资源文件 Android应用程序由Java开发,因此Java中许多实用的特性,在Android中也有体现.动态加载Class,也就是外部jar包,在 ...
- Android 中定义图片的资源文件
---恢复内容开始--- Android中定义图片的Id数组可以在java代码中直接通过new定义,之后使用,还有一种方法是在xml资源文件中直接定义,然后再java代码中通过函数可以获取xml代码中 ...
- 【Android】Android 中定义图片的资源文件
Android中定义图片的Id数组可以在java代码中直接通过new定义,之后使用,还有一种方法是在xml资源文件中直接定义,然后再java代码中通过函数可以获取xml代码中定义的资源文件.当然第二中 ...
- uniapp ios原生插件引入图片等资源文件方式
文章目录 一.前言 二.资源文件.bundle的存放位置 三.package.json 配置文件简单说明 resources 四.参考 一.前言 在uniapp官方文档上,对于依赖资源文件处理的提示是 ...
- opengl png图片 qt_Qt资源文件的格式,并用CMake添加Qt资源文件
目录 ......QRC文件的写法用CMake添加Qt资源文件添加QRC文件的函数步骤CPP中使用QRC文件使用QRC文件实例程序结果QRC文件CMakeLists.txt文件Dialog.h文件Di ...
- Qt笔记——添加菜单图片/添加资源文件
添加新文件,模板选择Qt分类中的Qt资源文件(Qt Resource File) 先添加前缀,点击"添加"按钮,然后选择"添加前缀",我们这里因为要添加图片,所 ...
- iOS开发那些事-iOS应用本地化-资源文件本地化
资源文件包括:图片文件.音频文件以及前文提到的Localizable.strings等文件,它们的特点是都是随着应用一起打包发布.但就本地化而言无论是图片文件还是音频文件都必须实现的步骤都是类似的,因 ...
- Amigo 学习(二)类和资源是怎么热更的?
转载请注明出处:https://juejin.im/post/5a712b696fb9a01cb74eacd6 写在开头 本文主要是跟着官方文档以自己的理解,捋一遍 Amigo 的流程. 在 GitH ...
最新文章
- Nature:“巨型原子”使芯片同时处理和收发量子信息成为可能
- 提升命令行效率的Bash快捷键
- java 线程接口_java - 实现线程的接口
- 电子产品的磨砂膜和镜面膜的选择
- 微服务 第六章 springboot 通过Spring-data-jpa 配置Oracle数据源(简单步骤)
- vba 指定列后插入列_Excle中的VBA介绍分享
- 如何在Win11上本地显示CPU、GPU和RAM使用情况?
- CppUnit快速入门
- sitck-breaking折棍法理解
- Java 排序算法:折半插入排序
- httpclient 下载大文件
- 安装loadrunner,缺少VC2005_sp1_with_atl的错
- 性能测试流程(超级详细)
- 佳能dpp4中文版 附使用教程
- watchOS7.2新增“心适能功能” 监测和分类心肺适能水平
- python抓取网站访客手机号_网站获取访客QQ系统
- iconfont显示小方块
- hashmap底层源码详解
- 职业测评让你更了解自己
- 咖说 | 揭秘佳士得首次拍卖的区块链艺术品Portraits of a Mind