UIImage, resolution independence and the iPhone 4′s Retina display
原文转自:http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/
iOS4 caters for the high-resolution Retina display that comes with the iPhone 4 by some rather clever abstraction, that moves away from the concept of ‘pixels’, and instead uses ‘points’, which are resolution-independent.
So, when you display an image that’s been prepared for the Retina display, it’s represented with a scale factor of 2, meaning that to your code, it appears to have the same dimensions, but in fact contains twice the information density.
iOS4′s UIImage makes it work by automatically looking for high-res images located alongside the prior ‘standard resolution’ ones — identified by a “@2x” suffix to the filename.
This works great with?+[UIImage imageNamed:]
, but although the?API documentation?says that other image loading methods will automatically load the @2x versions, they actually don’t. Yeah. Apple are working on it.
Until they sort themselves out, I’m using a convenience method sitting inside a UIImage category. So, where I would previously use something like?[UIImage imageWithContentsOfFile:]
, I now use?[UIImage imageWithContentsOfResolutionIndependentFile:]
.
?
Here’s the category:
@interface UIImage (TPAdditions)- (id)initWithContentsOfResolutionIndependentFile:(NSString *)path;+ (UIImage*)imageWithContentsOfResolutionIndependentFile:(NSString *)path;@end??@implementation UIImage (TPAdditions)?- (id)initWithContentsOfResolutionIndependentFile:(NSString *)path { if ( [[[UIDevice currentDevice] systemVersion] intValue] >= 4 && [[UIScreen mainScreen] scale] == 2.0 ) { NSString *path2x = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@@2x.%@", [[path lastPathComponent] stringByDeletingPathExtension], [path pathExtension]]];? if ( [[NSFileManager defaultManager] fileExistsAtPath:path2x] ) { return [self initWithCGImage:[[UIImage imageWithData:[NSData dataWithContentsOfFile:path2x]] CGImage] scale:2.0 orientation:UIImageOrientationUp]; } }? return [self initWithData:[NSData dataWithContentsOfFile:path]];}?+ (UIImage*)imageWithContentsOfResolutionIndependentFile:(NSString *)path { return [[[UIImage alloc] initWithContentsOfResolutionIndependentFile:path] autorelease];}?@end
This checks to see whether the iOS4 features are present, so this code should work on devices running prior OS versions as well.
What iOS4′s?imageWithContentsOfFile
?does?do is recognise if an image is the ’2x’ version, and sets the?scale
?accordingly, so it displays correctly.
Update: I just discovered that?-[UIDevice scale]
?actually exists?prior to iOS 4. Apple recommend using tests like?respondsToSelector
?to determine OS features, rather than version checks, but in this case, it gives the wrong result that can result in some pretty hard to find bugs. I’ve updated the above class to check the iOS version instead.
I’ve also avoided using?initWithContentsOfFile
?entirely: As Tea mentioned in a comment below, we probably shouldn’t be trusting this method any more, as it does not behave as advertised.
Update 2: I’ve been unable to replicate the problem, but a few commenters below noted issues with the 2x image being displayed at double-size. I’ve now updated the above to explicitly set the scale to 2.0 for the 2x image, which should fix the problem.
?