Question

I'm trying to write a Universal Application. The display should be slightly different for different screen resolutions. But when I code like this:

- (void)viewDidLoad {
    SCREEN_WIDTH=[[UIScreen mainScreen] applicationFrame].size.width;
    SCREEN_HEIGHT=[[UIScreen mainScreen] applicationFrame].size.height;
    NSLog(@"w:%f h:%f",SCREEN_WIDTH,SCREEN_HEIGHT);
...
}

I get output: w:320.000000 h:480.000000 even when the simulator is set to
Hardware->Device->iPhone (Retina)
Furthermore, images with this resolution display as full-screen images in the simulator.
I understand I should be getting w:640.000000 h:960.000000.
Is it like this for anyone else? And any ideas why/how to fix? See the related thread: here

Was it helpful?

Solution 2

Here is what I've found out. Since iOS4,

[[UIScreen mainScreen] applicationFrame].size.width; and

[[UIScreen mainScreen] applicationFrame].size.height;

give measurements in "points", not "pixels". For everything else, pixels=points, but for the iPhone4, each point has 4 pixels. Normal images are scaled in the iPhone4, so each pixel in the image is mapped onto a point. This means that the iPhone4 can run iPhone apps without a noticeable change.

The "apple" way to add "hi-res" images that take advantage of the iPhone's greater resolution is to replace ".png" with "@2x.png" in the image file name, and double the pixel density (effectively, just the width&height) in the image. Importantly, don't change the way the image is referred to in your code.
So if you have "img.png" in your code, iPhone4 will load the "img@2x.png" image if it is available.

The problem with this is that, if you are trying to develop a Universal app, and include separate images for all the different possible screen resolutions/pixel densities, your app will get bloated pretty quick.

A common solution to this problem is to pull all the required images of the 'net. This will make your binary nice and small. On the negative side, this will eat into your user's internet quota, and it will really annoy users who don't have wifi--especially if your app has no other reason to use the 'net (and you don't say your app needs the 'net in your app store description).

Fortunately, I have found another way. Often, when you scale down an image, the iPhone4 is clever enough to utilise the increased pixel density of the scaled image. For example, you might have:

UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100.0, 50.0)];
[indicatorButton setBackgroundImage:
   [UIImage imageNamed:@"buttonImage.png"] forState:UIControlStateNormal];

Now if buttonImage.png is 200x100, it will be perfectly well behaved on everything. Similarly, if you start with a nice 640x960 (pixel) image that displays quite nicely on the iPad and you scale it down to a 320x480 image for smaller screens, using something like:

+ (UIImage*)imageWithImage:(UIImage*)image newX:(float)newX newY:(float)newY{
    CGSize newSize=CGSizeMake((CGFloat)newX, (CGFloat)newY);
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0,0,newX,newY)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

It should display quite nicely on the iPhone4. The trick is not to double-up on your scaling. For example, if you do something like:

UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100.0, 50.0)];
    [indicatorButton setBackgroundImage:
       [Utilities imageWithImage:[UIImage imageNamed:@"buttonImage.png"] newX:100 newY:50] forState:UIControlStateNormal];

Then you'll have lost your pixel density and your image will look all "pixely" on the iPhone4.

Finally, if you want to detect if you are an iPhone4 (not really necessary if you use the above technique), the following code may be useful:

+(bool)imAnIphone4{
    return([[UIScreen mainScreen]respondsToSelector:@selector(scale)] && [UIScreen mainScreen].scale==2);
}

OTHER TIPS

UIScreen will always report the resolution of a Retina Display device as that of a non-Retina Display device. This allows old code to run transparently on such screens. However, UIScreen exposes a scale property which, when combined with the bounds of the screen, can be used to determine the physical pixel resolution of a device:

CGSize PhysicalPixelSizeOfScreen(UIScreen *s) {
    CGSize result = s.bounds.size;

    if ([s respondsToSelector: @selector(scale)]) {
        CGFloat scale = s.scale;
        result = CGSizeMake(result.width * scale, result.height * scale);
    }

    return result;
}

The resulting value on an iPhone 4 would be { 640.0, 960.0 }.

Did you rename the images as img.png@2x? And you should enable retina display in your code.

Even if you set simulator to retina display BUT the code is not retina display enabled, the graphics displayed out would be 320x480.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top