Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to develop or migrate apps for iPhone 5 screen resolution?
I was just wondering with how should we deal with the iPhone 5 bigger screen size.
As it has more pixels in height, things like GCRectMake that use coordinates (and just doubled the pixels with the retina/non retina problem) won't work seamlessly between versions, as it happened when we got the Retina.
And will we have to design two storyboards, just like for the iPad?
I personally don't think Apple will require you to check the screen size every time you have to draw something, like many answers say. Does that happen with the iPad?
All apps will continue to work in the vertically stretched screen from what I could tell in today's presentation. They will be letterboxed or basically the extra 88 points in height would simply be black.
If you only plan to support iOS 6+, then definitely consider using Auto Layout. It removes all fixed layout handling and instead uses constraints to lay things out. Nothing will be hard-coded, and your life will become a lot simpler.
However, if you have to support older iOS's, then it really depends on your application. A majority of applications that use a standard navigation bar, and/or tab bar, could simply expand the content in the middle to use up that extra points. Set the autoresizing mask of the center content to expand in both directions.
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
It works great out of the box for table views, however, if your app used pixel-perfect layout for displaying content, then your best bet would be to re-imagine the content so that it can accommodate varying heights.
If that's not a possibility, then the only remaining option is to have two UIs (pre iPhone 5, and iPhone 5).
If that sounds ugly, then you could go with the default letterboxed model where the extra points/pixels just show up black.
Edit
To enable your apps to work with iPhone 5, you need to add a retina version of the launcher image. It should be named Default-568h#2x.png. And it has to be retina quality - there's no backward compatibility here :)
You could also select this image from within Xcode. Go to the target, and under the Summary section, look for Launch Images. The image has to be 640x1136 pixels in size. Here's a screenshot of where to find it, if that helps.
You need to add a 640x1136 pixels PNG image (Default-568h#2x.png) as a 4 inch default splash image of your project, and it will use extra spaces (without efforts on simple table based applications, games will require more efforts).
I've created a small UIDevice category in order to deal with all screen resolutions. You can get it here, but the code is as follows:
File UIDevice+Resolutions.h:
enum {
UIDeviceResolution_Unknown = 0,
UIDeviceResolution_iPhoneStandard = 1, // iPhone 1,3,3GS Standard Display (320x480px)
UIDeviceResolution_iPhoneRetina4 = 2, // iPhone 4,4S Retina Display 3.5" (640x960px)
UIDeviceResolution_iPhoneRetina5 = 3, // iPhone 5 Retina Display 4" (640x1136px)
UIDeviceResolution_iPadStandard = 4, // iPad 1,2,mini Standard Display (1024x768px)
UIDeviceResolution_iPadRetina = 5 // iPad 3 Retina Display (2048x1536px)
}; typedef NSUInteger UIDeviceResolution;
#interface UIDevice (Resolutions)
- (UIDeviceResolution)resolution;
NSString *NSStringFromResolution(UIDeviceResolution resolution);
#end
File UIDevice+Resolutions.m:
#import "UIDevice+Resolutions.h"
#implementation UIDevice (Resolutions)
- (UIDeviceResolution)resolution
{
UIDeviceResolution resolution = UIDeviceResolution_Unknown;
UIScreen *mainScreen = [UIScreen mainScreen];
CGFloat scale = ([mainScreen respondsToSelector:#selector(scale)] ? mainScreen.scale : 1.0f);
CGFloat pixelHeight = (CGRectGetHeight(mainScreen.bounds) * scale);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
if (scale == 2.0f) {
if (pixelHeight == 960.0f)
resolution = UIDeviceResolution_iPhoneRetina4;
else if (pixelHeight == 1136.0f)
resolution = UIDeviceResolution_iPhoneRetina5;
} else if (scale == 1.0f && pixelHeight == 480.0f)
resolution = UIDeviceResolution_iPhoneStandard;
} else {
if (scale == 2.0f && pixelHeight == 2048.0f) {
resolution = UIDeviceResolution_iPadRetina;
} else if (scale == 1.0f && pixelHeight == 1024.0f) {
resolution = UIDeviceResolution_iPadStandard;
}
}
return resolution;
}
#end
This is how you need to use this code.
1) Add the above UIDevice+Resolutions.h & UIDevice+Resolutions.m files to your project
2) Add the line #import "UIDevice+Resolutions.h" to your ViewController.m
3) Add this code to check what versions of device you are dealing with
int valueDevice = [[UIDevice currentDevice] resolution];
NSLog(#"valueDevice: %d ...", valueDevice);
if (valueDevice == 0)
{
//unknow device - you got me!
}
else if (valueDevice == 1)
{
//standard iphone 3GS and lower
}
else if (valueDevice == 2)
{
//iphone 4 & 4S
}
else if (valueDevice == 3)
{
//iphone 5
}
else if (valueDevice == 4)
{
//ipad 2
}
else if (valueDevice == 5)
{
//ipad 3 - retina display
}
I have just finished updating and sending an iOS 6.0 version of one of my Apps to the store. This version is backwards compatible with iOS 5.0, thus I kept the shouldAutorotateToInterfaceOrientation: method and added the new ones as listed below.
I had to do the following:
Autorotation is changing in iOS 6. In iOS 6, the shouldAutorotateToInterfaceOrientation: method of UIViewController is deprecated. In its place, you should use the supportedInterfaceOrientationsForWindow: and shouldAutorotate methods.
Thus, I added these new methods (and kept the old for iOS 5 compatibility):
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
Used the view controller’s viewWillLayoutSubviews method and adjust the layout using the view’s bounds rectangle.
Modal view controllers: The willRotateToInterfaceOrientation:duration:,
willAnimateRotationToInterfaceOrientation:duration:, and
didRotateFromInterfaceOrientation: methods are no longer called on
any view controller that makes a full-screen presentation over
itself—for example, presentViewController:animated:completion:.
Then I fixed the autolayout for views that needed it.
Copied images from the simulator for startup view and views for the iTunes store into PhotoShop and exported them as png files.
The name of the default image is: Default-568h#2x.png and the size is 640×1136. It´s also allowed to supply 640×1096 for the same portrait mode (Statusbar removed). Similar sizes may also be supplied in landscape mode if your app only allows landscape orientation on the iPhone.
I have dropped backward compatibility for iOS 4. The main reason for that is because support for armv6 code has been dropped. Thus, all devices that I am able to support now (running armv7) can be upgraded to iOS 5.
I am also generation armv7s code to support the iPhone 5 and thus can
not use any third party frameworks (as Admob etc.) until they are
updated.
That was all but just remember to test the autorotation in iOS 5 and iOS 6 because of the changes in rotation.
No.
if ([[UIScreen mainScreen] bounds].size.height > 960)
on iPhone 5 is wrong
if ([[UIScreen mainScreen] bounds].size.height == 568)
#interface UIDevice (Screen)
typedef enum
{
iPhone = 1 << 1,
iPhoneRetina = 1 << 2,
iPhone5 = 1 << 3,
iPad = 1 << 4,
iPadRetina = 1 << 5
} DeviceType;
+ (DeviceType)deviceType;
#end
.m
#import "UIDevice+Screen.h"
#implementation UIDevice (Screen)
+ (DeviceType)deviceType
{
DeviceType thisDevice = 0;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
thisDevice |= iPhone;
if ([[UIScreen mainScreen] respondsToSelector: #selector(scale)])
{
thisDevice |= iPhoneRetina;
if ([[UIScreen mainScreen] bounds].size.height == 568)
thisDevice |= iPhone5;
}
}
else
{
thisDevice |= iPad;
if ([[UIScreen mainScreen] respondsToSelector: #selector(scale)])
thisDevice |= iPadRetina;
}
return thisDevice;
}
#end
This way, if you want to detect whether it is just an iPhone or iPad (regardless of screen-size), you just use:
if ([UIDevice deviceType] & iPhone)
or
if ([UIDevice deviceType] & iPad)
If you want to detect just the iPhone 5, you can use
if ([UIDevice deviceType] & iPhone5)
As opposed to Malcoms answer where you would need to check just to figure out if it's an iPhone,
if ([UIDevice currentResolution] == UIDevice_iPhoneHiRes ||
[UIDevice currentResolution] == UIDevice_iPhoneStandardRes ||
[UIDevice currentResolution] == UIDevice_iPhoneTallerHiRes)`
Neither way has a major advantage over one another, it is just a personal preference.
#Pascal's comment on the OP's question is right. By simply adding the image, it removes the black borders and the app will use the full height.
You will need to make adjustments to any CGRects by determining that the device is using the bigger display. I.e. If you need something aligned to the bottom of the screen.
I am sure there is a built in method, but I haven't seen anything and a lot is still under NDA so the method we use in our apps is quite simply a global function. Add the following to your .pch file and then its a simple if( is4InchRetina() ) { ... } call to make adjustments to your CGRects etc.
static BOOL is4InchRetina()
{
if (![UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 548 || [UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 568)
return YES;
return NO;
}
I think you can use [UIScreen mainScreen].bounds.size.height and calculate step for your objects. when you calculate step you can set coordinates for two resolutions.
Or you can get height like above and if(iphone5) then... else if(iphone4) then... else if(ipad). Something like this.
If you use storyboards then you have to create new for new iPhone i think.
As it has more pixels in height, things like GCRectMake that use coordinates won't work seamlessly between versions, as it happened when we got the Retina.
Well, they do work the same with Retina displays - it's just that 1 unit in the CoreGraphics coordinate system will correspond to 2 physical pixels, but you don't/didn't have to do anything, the logic stayed the same. (Have you actually tried to run one of your non-retina apps on a retina iPhone, ever?)
For the actual question: that's why you shouldn't use explicit CGRectMakes and co... That's why you have stuff like [[UIScreen mainScreen] applicationFrame].
Xcode offers asset buckets for 1x, 2x, 4" 2x, and 3x assets. My fullscreen assets are all wonky with this configuration, because the 2x bucket is used for 3.5" and 4.7" screens. Currently I have a UIImage category that introspects the current screen size, and selects a "*-3.5" asset if the device seems to be 3.5".
This is clunky and not cool. Seeing that Xcode caters to all the different device sizes for their LaunchImage asset, I was hoping there was some way to supply device specific assets for non launch image assets without resorting to code.
I have reported a bug to Apple about this since mid November 2014 and I just noticed they marked it as No Value... which gives me the impression Apple has omitted an additional slot for iPhone 6 on purpose. My guess is they now want the 2x slot to be used for iPhone 6, and maybe they're reducing support to iPhone 4s as it's getting old.
If you really want to keep supporting the iPhone 4s, I'd suggest to use iPhone 6 sized images in the 2x slot, and then use the following method to load your images:
+(UIImage *)loadImageNamed:(NSString *)imageName
{
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGFloat screenHeight = MAX(screenSize.width, screenSize.height);
CGFloat const IPHONE_4_SCREEN_HEIGHT = 480;
UIImage *image = [UIImage imageNamed:imageName];
if(screenHeight == IPHONE_4_SCREEN_HEIGHT) {
CGFloat const xScale = .85333333;//x conversion ratio from iPhone 6's 375 pts width screen to iPhone 4's 320 pts width screen
CGFloat const yScale = .71964018;//y conversion ratio from iPhone 6's 667 pts height screen to iPhone 4's 480 pts height screen
CGSize newSize = CGSizeMake(xScale * image.size.width, yScale * image.size.height);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
[image drawInRect:(CGRect){0, 0, newSize}];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resizedImage;
}
return image;
}
Resizing a big image (iPhone 6) to a smaller one (iPhone 4) doesn't lose much quality even if the aspect ration is not the same.
Using an existing project when moving to Xcode 6 and iOS 8 creates some initial issues. I solved this by changing the image set from Device specific to Universal. This removes the R4 image option and leaves you with #1x, #2xand #3x. If you use for example a background image that needs to fit the screen then I will recommend that you find an image that does not have to fit 100 % perfect to look good, and set image to be displayed as Aspect Fill.
I have the same problem and got confirmation from apple that I have to wrote code for that. For example you can try like this Fullscreen images on iPhone 6 with Asset Catalogs
But I actually went lazy about it by using one 2x for 4" & 4.7" screen and another 2x for 3.5" screen
Say I want a bundled image to take up all available screen width in an iPhone app - for example a banner. I'd create my_banner.png with width 320px, my_banner#2x.png with width 640px and my_banner#3x.png for iPhone 6 plus with width 1242px. But the resolution of iPhone 6 is 750×1334 pixels. Still it shares the #2x suffix with iPhone 4 and 5 that have 640px width.
What's the recommended way or a good way to specify an image file that has been optimised for the 750px width of iPhone 6? Seems like it cannot be done in an asset catalog? Should it be done programatically? Is there some other suffix that can be used for iPhone 6?
(Image extracted from http://www.iphoneresolution.com)
It seems to me that a lot of these answers want to address how to constrain the imageView, where I think you are concerned with loading the correct media file? I would come up with my own future extensible solution, something like this:
"UIImage+DeviceSpecificMedia.h" - (a category on UIImage)
Interface:
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, thisDeviceClass) {
thisDeviceClass_iPhone,
thisDeviceClass_iPhoneRetina,
thisDeviceClass_iPhone5,
thisDeviceClass_iPhone6,
thisDeviceClass_iPhone6plus,
// we can add new devices when we become aware of them
thisDeviceClass_iPad,
thisDeviceClass_iPadRetina,
thisDeviceClass_unknown
};
thisDeviceClass currentDeviceClass();
#interface UIImage (DeviceSpecificMedia)
+ (instancetype )imageForDeviceWithName:(NSString *)fileName;
#end
Implementation:
#import "UIImage+DeviceSpecificMedia.h"
thisDeviceClass currentDeviceClass() {
CGFloat greaterPixelDimension = (CGFloat) fmaxf(((float)[[UIScreen mainScreen]bounds].size.height),
((float)[[UIScreen mainScreen]bounds].size.width));
switch ((NSInteger)greaterPixelDimension) {
case 480:
return (( [[UIScreen mainScreen]scale] > 1.0) ? thisDeviceClass_iPhoneRetina : thisDeviceClass_iPhone );
break;
case 568:
return thisDeviceClass_iPhone5;
break;
case 667:
return thisDeviceClass_iPhone6;
break;
case 736:
return thisDeviceClass_iPhone6plus;
break;
case 1024:
return (( [[UIScreen mainScreen]scale] > 1.0) ? thisDeviceClass_iPadRetina : thisDeviceClass_iPad );
break;
default:
return thisDeviceClass_unknown;
break;
}
}
#implementation UIImage (deviceSpecificMedia)
+ (NSString *)magicSuffixForDevice
{
switch (currentDeviceClass()) {
case thisDeviceClass_iPhone:
return #"";
break;
case thisDeviceClass_iPhoneRetina:
return #"#2x";
break;
case thisDeviceClass_iPhone5:
return #"-568h#2x";
break;
case thisDeviceClass_iPhone6:
return #"-667h#2x"; //or some other arbitrary string..
break;
case thisDeviceClass_iPhone6plus:
return #"-736h#3x";
break;
case thisDeviceClass_iPad:
return #"~ipad";
break;
case thisDeviceClass_iPadRetina:
return #"~ipad#2x";
break;
case thisDeviceClass_unknown:
default:
return #"";
break;
}
}
+ (instancetype )imageForDeviceWithName:(NSString *)fileName
{
UIImage *result = nil;
NSString *nameWithSuffix = [fileName stringByAppendingString:[UIImage magicSuffixForDevice]];
result = [UIImage imageNamed:nameWithSuffix];
if (!result) {
result = [UIImage imageNamed:fileName];
}
return result;
}
#end
I am using the following trick as some stuff actually works:
Asset Catalog for specific devices
Specify images for 1x, 2x on the base of 320x640
Specify images for 4 2x and 3x on the base of 320x568 (iPhone 5)
Create a new Images set for the iPhone 6 specifically (as this is the only device that makes trouble with edge to edge bindings)
Only provide 2x image for iPhone 6 in full resolution (750x1334)
Declare a constant
#define IS_IPHONE_6 [[UIScreen mainScreen]nativeBounds].size.width == 750.0 ? true : false
and use it like this:
UIImage *image = [UIImage imageNamed:#"Default_Image_Name"];
if(IS_IPHONE_^) {
image = [UIImage imageNamed:#"Iphone6_Image_Name"];
}
this might be not the most beautiful solution, but it works, at least as long as apple does not provide a better API for edge to edge bindings.
Auto Layout is supposed to help with this situation..
Now tell me #Nicklas Berglund what would you do if the device rotates? Lets say you are in landscape mode now.. How would you fill the Horizontal space which is not in the image assets any more?
Just food for thoughts.. Auto Layout supposed to take care of your screen no matter which orientation, or which device you are running your app on..
Maybe Apple should start targeting device orientations in image assets in future?
Lets go back to your question.. The solution is to replace your #2x images with 750px wide images and then have Auto Layout do its job. Oh yea, this is the tricky part..
If you just add constraints to fit it, it will squeeze it horizontally when displayed in 4" screen, but you can use multipliers to scale the image appropriately. Here's how you can do it:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[imageFooterView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(imageFooterView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[imageFooterView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(imageFooterView)]];
float aspectRatio = imageFooterView.frame.size.height/imageFooterView.frame.size.width;
[imageFooterView addConstraint:[NSLayoutConstraint constraintWithItem:imageFooterView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:imageFooterView attribute:NSLayoutAttributeWidth multiplier:aspectRatio constant:0.0f]];
I couldn't find a way to do it either, as I had a background Image that was perfectly sized with the Asset Catalog on every device except the iPhone 6. My fix (I did this in SpriteKit)?
if (bgNode.size.width != self.frame.size.width) {
bgNode.texture = [SKTexture textureWithImageNamed:#"i6bg.png"];
[bgNode runAction:[SKAction scaleXTo:self.frame.size.width/bgNode.size.width y:self.frame.size.width/bgNode.size.height duration:.1]];
}
bgNode is the background image that is pulled up by the device. If it's an iPhone 6, it won't fit the screen and so the background image width wont be the same as the screen width. When the device is recognized as an iPhone 6, I change the texture to the R4 texture (the #2x for retina) and scale it to the correct dimensions.
I tried doing the same with the regular #2x image, but the scaled image looked very bad (it was too stretched out and noticable). With the R4 texture scaled, the proportions of width/height are a bit better and so the change isn't even noticeable. I hope this gives you some idea as to what you can do before Apple adds an iPhone 6 Asset.
Hope this will solve all your issues related to customised edge to edge image.
Xcode 6 - xcassets for universal image support
Make sure if you are using auto layout then check pin is set to zero for all edges and constraints to margin is un checked.
You can also visit this links for launch screen images:
http://www.paintcodeapp.com/news/iphone-6-screens-demystified
http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
I raised the same question to apple technical support and they confirm that for fullscreen image it can't be done in asset catalog: "Currently, there is no way for the Asset Catalog to load device specific images. If your app needs to support device specific images you will need to implement your own code to detect the screen size and choose the appropriate image. You can file an enhancement request by using the following link. Be sure to explain your use case for this feature. "
I checked the naming convention of a launch image generated from an asset catalog via Xcode 6 and the landscape version for iPhone 6+, for example, had: LaunchImage-Landscape-736h#3x.png
Based on that, I'd presume it would be as follows, for retina devices, assuming a base file desert.png:
desert#2x : iPhone 4s (320 x 420)
desert-568h#2x : iPhones 5, 5C and 5S (320 x 568)
desert-667h#2x : iPhone 6 (375 x 667)
desert-736h#3x : iPhone 6+ (414 x 736)
desert#2x~ipad : iPad (1024 x 768)
There is no native Assets support for this case, so I think it would be better to do it manually as working with undocumented file names may break easily in the future.
Just measure the device dimensions and call the image that you want. ie Do it programatically
So in your appdelegate have globals
deviceHeight = self.window.frame.size.height;
deviceWidth = self.window.frame.size.width;
that you can call repeatedly.
Then check them and call the appropriate image
if (deviceWidth == 640){
image = IPHONE4IMAGE;
deviceString = #"iPhone4";
}
else...
In my case, I was interested in making my base view controller subclass have the same background image as my launch image.
NOTE: This approach will not work unless this is your specific requirement.
Also, even when I tried creating a background image that was the correct size for the iPhone 6 (750x1334), loading that image as a pattern image into a background color for a view ended up scaling the image up in an undesirable way.
This answer gave me the code that I needed to figure out a good solution for me.
Here's the code I got working to have my launch image match my UIViewController's background image (or vice versa):
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *background = [UIImage imageNamed:[self splashImageName]];
UIColor *backgroundColor = [UIColor colorWithPatternImage:background];
self.view.backgroundColor = backgroundColor;
}
- (NSString *)splashImageName {
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGSize viewSize = self.view.bounds.size;
NSString *viewOrientation = #"Portrait";
if (UIDeviceOrientationIsLandscape(orientation)) {
viewSize = CGSizeMake(viewSize.height, viewSize.width);
viewOrientation = #"Landscape";
}
NSArray *imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:#"UILaunchImages"];
for (NSDictionary *dict in imagesDict) {
CGSize imageSize = CGSizeFromString(dict[#"UILaunchImageSize"]);
if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[#"UILaunchImageOrientation"]])
return dict[#"UILaunchImageName"];
}
return nil;
}
Please try this class to change the image name programmatically.
import UIKit
class AGTools: NSObject {
class func fullWidthImage(imageName: String!) -> String!{
let screenWidth = UIScreen.mainScreen().bounds.size.width
switch (screenWidth){
case 320:
// scale 2x or 1x
return (UIScreen.mainScreen().scale > 1.0) ? "\(imageName)#2x" : imageName
case 375:
return "\(imageName)-375w#2x"
case 414:
return "\(imageName)-414w#3x"
default:
return imageName
}
}
}
use this method like this.
_imgTest.image = UIImage(named: AGTools.fullWidthImage("imageName"))
FIRST of all, you need to configure your imageView to cover all the screen, Autolayout will help a lot for this job, take a look on the link below and find how to Pin the constraints (Leading Space, Trailing Space, Top Space and Bottom Space) using Storyboards:
http://www.thinkandbuild.it/learn-to-love-auto-layout/
SECOND step is create device specific image sets on your image assets (image below), to display different images according to device.
Check out this infographic:
http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
It explains the differences between old iPhones, iPhone 6 and iPhone 6 Plus. You can see comparison of screen sizes in points, rendered pixels and physical pixels
That's all
Please, give a feedback if you have any trouble.
I'm relatively new in iOS development.
I'm currently building an app using the cocos2d library that will be available for the iPad Retina, iPad, iPhone 5, and iPhone 4s/4.
I'm getting all of my images setup, and I'm trying to figure out the naming conventions.
Does anyone know of a guide out there that could help me?
Say I have a background.png.
From what I understand:
background.png -> iPhone (non-retina/fallback)
background-hd.png -> iPhone 4s/4 (retina)
background-ipad.png -> iPad (non-retina)
background-ipadhd.png -> iPad (retina)
And the same naming convention would be used for all other files? For example:
arbitraryButton.png -> iPhone (non-retina/fallback)
arbitraryButton-hd.png -> iPhone 4s/4 (retina)
arbitraryButton-ipad.png -> iPad (non-retina)
arbitraryButton-ipadhd.png -> iPad (retina)
What do I name the iPhone 5 files?
I've searched a bit and cant seem to find any tangible guides out there on this.
Thank you!
The OS has a naming convention that you can use (and enforces for you, meaning you only need to reference the file as #"fileName"). The documentation is available here.
fileName.png -> iPhone (non-retina/fallback)
fileName#2x.png -> iPhone 4s/4 (retina)
fileName~ipad.png -> iPad (non-retina)
fileName#2x~ipad.png -> iPad (retina)
Note: ~iphone also exists, and can be used with/instead of using ~ipad. Using both ~ipad and ~iphone would safeguard against a third idiom Apple may introduce. cough TV cough
As for the iPhone 5, the OS does not enforce a naming scheme. But, it'd probably be wise to use the same scheme as that for the launch image.
fileName-568h#2x.png -> iPhone 5
To handle this easily throughout the app, you can create a category, and use it where you know you will have an iPhone 5 friendly image, as well as a regular sized image. A simple version can be made, like the one below.
UIImage+iPhone5Image.h
#import <UIKit/UIKit.h>
#interface UIImage (iPhone5Image)
+ (UIImage*)iPhone5ImageNamed:(NSString*)imageName;
#end
UIImage+iPhone5Image.m
#import "UIImage+iPhone5Image.h"
#define IsIPhone5() ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone && [UIScreen mainScreen].bounds.size.height == 568)
#implementation UIImage (iPhone5Image)
+ (UIImage*)iPhone5ImageNamed:(NSString*)imageName
{
if (IsIPhone5()) {
NSString* newImageName = [NSString stringWithFormat:#"%#-568h", imageName];
return [UIImage imageNamed:newImageName];
}
else {
return [UIImage imageNamed:imageName];
}
}
#end
It looks like you are after the cocos2d naming conventions not the standard UIKit versions. They are different and if you are using cocos2d you are recommended to use the cocos2d suffixes and not the UIKit ones.
They are as follows:
Non retina iPhone (No suffix)
Retina iPhone -hd
Non retina iPad -ipad
Retina iPad -ipadhd
iPhone 5 -iphone5 and -iphone5hd
All files that you want loaded based on the device that are used with the cocos2d methods can be suffixed like this.
Ok, Now cocos2d itself support iphone5.
-hd.png for iPhone HD
-ipad.png for iPad
-ipadhd.png for iPad HD
-wide.png for iphone 5
-widehd.png for iPhone 5 HD
If your Cocos2d version is old then use:
static inline NSString *i5res(NSString * data)
{
if(IS_IPHONE5)
{
return [data stringByReplacingOccurrencesOfString:#"." withString:#"-whd."];
}
return data;
}
//usage
CCSprite *bg = [CCSprite spriteWithFile:i5res(#"bg.png")];
For the compiler to automatically choose the right image you will want to name the standard (non-retina) images image.png and the retina images image#2x.png. Then in your code just refer to the standard one. The compiler will do the rest. So if you are setting an image it should look like this:
UIImage *anImage = [UIImage imageNamed:#"image.png"];
There isnt a specific naming convention for the iPhone 5, because the app won't automatically choose a different image size for the iPhone 5, you will have to do that in your code with something like this:
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenHeight = screenRect.size.height;
if([[UIScreen mainScreen]bounds].size.height == 568){
UIImage *signUp = [UIImage imageNamed:#"signup-bg-568h.jpg"];
[signUpImage setImage:signUp];
}
else{
UIImage *signUp = [UIImage imageNamed:#"signup.jpg"];
[signUpImage setImage:signUp];
}
I have in my viewController.m written the background code:
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"image.png"]];
And I have the correct names of the different pictures:
image.png for non-retina display (320x480)
image#2x.png for retina display (640x960)
image-568h#2x.png for iPhone 5 (640x1136)
But when I run it in the simulator it does not take the image-568h#2x.png for iPhone 5 screen it only takes the image#2x for 4s screen and scale it to fit the screen... I dont know if there is any coding to use the image-568h#2x for iPhone 5 screen?
Im using Xcode 4.5
iPhone 5 is retina, just like iPhone 4 and 4S, and the #2x-image will be used automatically for all these devices. It's only the startup-image that is called "-568h#2x" for iPhone 5. You need to write some code to use a different image, something like this would work:
NSString *filename = #"image.png";
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height == 568.0f)
filename = [filename stringByReplacingOccurrencesOfString:#".png" withString:#"-568h.png"];
imageView.image = [UIImage imageNamed:filename];
if you are trying to use [UIImage imageNamed:#"image.png"] and expect image-568h#2x.png to be picked automatically from the bundle for iPhone 5, it will not work.
Automatic picking works only for iPhone 4 and 4S.
Only the Default image named as Default-568h#2x.png will be picked automatically in iPhone 5.
for normal images, if you have separate image for iPhone 5, try using this code
CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (screenBounds.size.height == 568) {
// code for 4-inch screen
} else {
// code for 3.5-inch screen
}
I believe it is incorrect to assume that you can apply the -568h#2x trick to all image files. I think it only works for Default-568h#2x.png. This is the file that iOS looks for at app launch on a 4" display device, as well as the "flag" to enable 4" display support in the SDK. For example, once you include this specific file, your table views will fill the screen.
I have not read anything to suggest that you can simply provide any image with the -568h#2x file name component and have it be used automagically. You'll have to do that yourself based on the screen size, e.g. [UIScreen mainScreen].bounds.size.height.