iOS 一套@3x图片兼容所有iOS设备和系统
特别申明:本文使用的方法采用了苹果私有类UIImageNibPlaceholder,上传AppStore有被拒风险,只发企业版的可忽略本申明
自从iPhone6和iPhone6+出来了以后,iOS开发的程序猿从此走上了和android一样的道路,各种适配,头都大了。特别是万恶的iPhone6+,本来就被图片塞的很臃肿的app现在又要加一套@3x的图片,要知道这一套图片能把app撑大一倍呀。而且@3x图片完全可以压缩成@2x和@1 x的图片,于是我毅然踏上的用一套图片兼容所有设备的道路。历经千辛万苦,摸爬于各大外国论坛,终于让我找到了一个可行的方法。
废话不多说,先上代码:
UIImage+LocalImage.h
#import <UIKit/UIKit.h> @interface UIImage (LocalImage) /** 将原本3倍尺寸的图片缩放到设备对应尺寸 */ - (UIImage *)scaledImageFrom3x; @end
UIImage+LocalImage.m
#import "UIImage+LocalImage.h" #import <objc/runtime.h> // 当前iOS版本 #ifndef __CUR_IOS_VERSION #define __CUR_IOS_VERSION ([[[UIDevice currentDevice] systemVersion] floatValue] * 10000) #endif @implementation UIImage (LocalImage) + (void)load { if (__CUR_IOS_VERSION >= __IPHONE_8_0) { // 由于iOS8已经兼容,所以不需要使用下面方法 return; } // 改替换实现用代码调用imageNamed:时的图片适应 SEL origM = @selector(imageNamed:); SEL newM = @selector(imageWithName:); method_exchangeImplementations(class_getClassMethod(self, origM), class_getClassMethod(self, newM)); // 该替换实现对xib中图片的适应 NSString *className = [[@"UIImage" stringByAppendingString:@"Nib"] stringByAppendingString:@"Placeholder"]; // 这样写是为了避开AppStore审核的代码检查,不一定有效 Method m1 = class_getInstanceMethod(NSClassFromString(className), @selector(initWithCoder:)); Method m2 = class_getInstanceMethod(self, @selector(initWithCoderForNib:)); method_exchangeImplementations(m1, m2); } /** 该方法替换原有的imageNamed:方法 */ + (UIImage *)imageWithName:(NSString *)name { UIImage *aImage = [self imageWithName:name]; if (aImage) { // 如果能取到对应图片,则直接返回 return aImage; } NSString *fileName = [name stringByAppendingString:@"@3x.png"]; aImage = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName]]; return [aImage scaledImageFrom3x]; } /** 该方法替换UIImage-Nib-Placeholder中的initWithCoder:,因为xib的图片都是用这个类来初始化的 */ - (id)initWithCoderForNib:(NSCoder *)aDecoder { NSString *resourceName = [aDecoder decodeObjectForKey:@"UIResourceName"]; NSString *newResourceName = resourceName; if ([resourceName hasSuffix:@".png"]) { newResourceName = [resourceName substringToIndex:resourceName.length -4]; } return [UIImage imageNamed:newResourceName]; } /** 将原本3倍尺寸的图片缩放到设备对应尺寸 */ - (UIImage *)scaledImageFrom3x { float locScale = [UIScreen mainScreen].scale; float theRate = 1.0 / 3.0; UIImage *newImage = nil; CGSize oldSize = self.size; CGFloat scaledWidth = oldSize.width * theRate; CGFloat scaledHeight = oldSize.height * theRate; CGRect scaledRect = CGRectZero; scaledRect.size.width = scaledWidth; scaledRect.size.height = scaledHeight; UIGraphicsBeginImageContextWithOptions(scaledRect.size, NO, locScale); [self drawInRect:scaledRect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if(newImage == nil) { NSLog(@"could not scale image"); } return newImage; }
使用方法:只需要将这两个类导入到项目中即可,不需要在其他类中import。也不需要修改原来生成加载图片的方法,也不需要修改xib加载图片的方法,不过一定要确保有一套@3x的图片
该方法仅作用于iOS8一下的系统,因为经过验证,iOS8以上的系统都已经自动对图片进行适配了。
分享一下在探索该方法时收藏的一下网址。
1、Google搜索镜像(相信很多人都有好久没用google了吧):https://github.com/greatfire/wiki
2、苹果私有类(原来苹果有这么多东西藏着掖着呀):https://github.com/kennytm/iphone-private-frameworks/tree/master
3、两个提供重要帮助的帖子:
http://w3facility.org/question/are-images-assigned-in-a-xib-cached/
希望该方法能对大家有帮助。转载请注明出处哦
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。