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.

 

你可能感兴趣的:(display)