3

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

Community
  • 1
  • 1
iPadDeveloper2011
  • 4,560
  • 1
  • 25
  • 36

3 Answers3

5

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 }.

Jonathan Grynspan
  • 43,286
  • 8
  • 74
  • 104
  • OK, thanks. However it looks like if I had a 640x960 image, it would not display correctly on the iPhone4. Is there some "switch" I can "flick" somewhere to get this to work? – iPadDeveloper2011 Jan 23 '11 at 09:44
  • Google is your friend. You should go read up on exactly what you're doing. Apple has a wealth of information on their website: http://www.google.com/search?client=safari&rls=en&q=site:developer.apple.com+retina+display&ie=UTF-8&oe=UTF-8 – Jonathan Grynspan Jan 23 '11 at 10:08
  • Hi again. I found a good discussion about this: http://www.markj.net/iphone-4-2x-graphics-scale-ipad/ Apple's "quick fix" of just adding images with @2x in the file name seems pretty horrible to me--my app is fine on iPad, iPod t, and iPhone (using scaled down images) but it now seems like it will be crap on iPhone4. :-(. – iPadDeveloper2011 Jan 23 '11 at 10:13
  • Is there a reason you think you can't use this system? It's not difficult. – Jonathan Grynspan Jan 23 '11 at 10:15
  • 3
    Hi Jonathan, Sorry, but I find your "Google is your friend" comment pretty annoying. I've read through the first 3 links in the google page you sent, and found nothing useful. Yes, apple has heaps of info on their site--is any of it actually applicable to my question however? – iPadDeveloper2011 Jan 23 '11 at 10:19
  • Having shipped a number of apps that take advantage of the Retina Display, I would say that yes, those links explain pretty thoroughly what you need to know. – Jonathan Grynspan Jan 23 '11 at 10:21
  • I think I may have to do something like the following: rename _all_ my images, "...@2x..." (and also in my code) then, I "sense" if I'm an iPhone. If I am, I remove the "...@2x..." from my image names in my code (so apple can "add it back in automatically"). Only in that way can I avoid bloating my app with heaps of unnecessary images. – iPadDeveloper2011 Jan 23 '11 at 10:27
  • I don't think they do... I can't even find any mention of "...@2x..." in any of them. Congrats on your apps. – iPadDeveloper2011 Jan 23 '11 at 10:32
  • Perhaps apple creates different executables for iPad, iPhone4,iPhone,... and only includes the necessary images? If so, what images would be included for iPad? Anyone know? – iPadDeveloper2011 Jan 23 '11 at 10:46
  • Apple uses the same binary files for all devices. You don't have to make any changes to your code to incorporate the @2x variants. When you call `[UIImage imageNamed: @"foo.png"]` it will pick "foo@2x.png" automatically for you on devices that need it. – Jonathan Grynspan Jan 23 '11 at 16:23
  • OK, thanks Jonathan. The problem with that is that if my Universal app includes old iPhone images, iPhone4 images, and iPad images, it is really bloated. I guess that is why people write their apps to pull the required images off the 'net now... – iPadDeveloper2011 Jan 24 '11 at 00:49
  • That's how apps are built on iPhone. Just go with it--if your images are really that huge, that is an entirely separate issue. – Jonathan Grynspan Jan 24 '11 at 02:00
3

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);
}
iPadDeveloper2011
  • 4,560
  • 1
  • 25
  • 36
  • I'm trying to resolve an issue relating to your above solution; but I don't want to clog up the post. If you have a spare moment can you shoot me a quick email (you can see it from my user profile); thanks! – KeithComito Apr 06 '11 at 20:32
  • user201926. I think only you can see your email in your profile (I can't). I can see my email in mine, but I guess you can't. Regardless--if your question is genuinely closely related, please share. Otherwise, consider asking your own question. – iPadDeveloper2011 Apr 08 '11 at 03:23
1

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.

Franci Penov
  • 74,861
  • 18
  • 132
  • 169
xuanweng
  • 1,939
  • 1
  • 11
  • 10
  • No I didn't. I have a fn. that scales images to a given w and h, and I just pass it SCREEN_WIDTH and SCREEN_HEIGHT (for my fullscreen images). – iPadDeveloper2011 Jan 23 '11 at 09:05
  • Scaling? Resolution would b blurry.. Not advised.. Try find the actual way of doing it.. – xuanweng Jan 23 '11 at 09:09
  • Mmmm? Please clarify how I can get SCREEN_WIDTH=[[UIScreen mainScreen] applicationFrame].size.width; to be 640 when the simulator is set to retina display!? Scaling works well as long as I scale down. I start with iPad resolution images... I have also found that scaling up works well if I need to speed-up an animation (where the frames don't otherwise render fast enough) – iPadDeveloper2011 Jan 23 '11 at 09:10
  • U can try this link: http://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BuildTimeConfiguration/BuildTimeConfiguration.html#//apple_ref/doc/uid/TP40007072-CH7-SW24 – xuanweng Jan 23 '11 at 09:24
  • 1
    Just to let you have a clearer idea, ipad resolution ratio is differ than those of iphone.. Ipad is 4:3 where iphone is 16:9.. Dont be lazy and create 3 set of images.. Haha.. – xuanweng Jan 23 '11 at 09:28
  • Thanks--However I've looked at that link before, and have just scanned through it again and haven't found anything useful. – iPadDeveloper2011 Jan 23 '11 at 09:31
  • Mmmm... 3 sets of images would make my app unreasonably large. BTW, if my build setting target iphone/ipad, there appears to be no way to make the simulator launch as an iPad. – iPadDeveloper2011 Jan 23 '11 at 09:40
  • hmmm.. yea.. i understand that.. here is how apple detects the images: When you set to iphone only and your images you did not specify retina support, it loads the file called img.png. Images may appear blurry when on retina display. When you specify retina support, IT EXPECTS img.png@2x to be found in your resources. Even if in your code you write load img.png, it would still look for img.png@2x. I think its the same for ipad version as well.. – xuanweng Jan 23 '11 at 14:23
  • Hi Xuanweng. Thanks for your comments. However, my understanding is that I don't need to "specify retina support"--I just need to add the "...@2x.png" (_not_ "... .png@2x") files. I believe the pixel densities are 326ppi for the iPhone 4, 163ppi for older iPhones, and 132ppi for the iPad. I'm not really sure if setting the pixel densities for the png images really effects how the image is displayed. I think a 640x960 (pixel) "img@2x.png" image will be displayed as fullscreen in the iPhone4, no matter what it says its pixel density is.(?) – iPadDeveloper2011 Jan 24 '11 at 01:15