Query launch image at runtime - ios

I'd like to have a nice start of my app by fading from the splash screen (UILaunchImageFile) into the main screen. Easy thing, I thought, just show an UIImageView with the splash screen as the very first view and then make a transition animation.
The problem is, since this is an iPad app with all four orientations supported, and splash screens for all these orientations, I would need to query which splash screen was used. I could query the current device rotation and select the image accordingly, but I wonder whether there's a better way.
So, can I query somehow which launch image was used during app start or do I need to ask for the device's current UI orientation and chose the file accordingly ?

No, you can't do this automagically. Querying the device rotation and selecting an image based on that is perfectly fine.
You really only need Portrait or Landscape in this situation though, assuming you are rotating your view properly.

As already stated by Joshua you cannot, as far as I am aware.
In case this might help someone else, if you are using asset catelogs the following code should provide the correct launch image for the current interface orientation.
NSString *suffix = nil;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
suffix = [[UIScreen mainScreen] bounds].size.height >= 568.0f ? #"-568h#2x" : #"#2x";
}
else {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
suffix = UIInterfaceOrientationIsPortrait(orientation) ? #"-Portrait" : #"-Landscape";
suffix = [UIScreen mainScreen].scale == 2.0 ? [suffix stringByAppendingString:#"#2x~ipad"] : [suffix stringByAppendingString:#"~ipad"];
}
NSString *launchImageName = [NSString stringWithFormat:#"LaunchImage-700%#.png",suffix];

Related

IOS Swift App how to vary my constraints as per different iphone size like iphone 8, iphone 5 iphone SE [duplicate]

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

Autolayout: UIImageView not rotating with device orientation

There's probably a dozen SO questions with similar titles, and as far as I can see, I've incorporated the advice from every one of them, with no luck. When I rotate the device from portrait to landscape, I want to change the background image. However, in every experiment I have tried, the UIImageView in landscape remains portrait sized.
I am using Autolayout, configured in IB like so:
My view hierarchy is configured like so:
When I rotate the device, I want to rotate everything in UIView viewBackground (the image and all of the buttons). I believe I can manage the button movements through constraints, but need to rotate UIImageView image view background myself. So, I added the following code:
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
int scaleFactor = self.traitCollection.displayScale;
NSString *source = #"drawn";
NSString *orientation;
if (size.width > size.height)
{
orientation = #"Landscape";
}
else
{
orientation = #"Portrait";
}
NSString *platform;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
platform = #"iPad";
}
else
{
platform = #"iPhone";
}
NSString *filename = [NSString stringWithFormat:#"%# %# %# %.0fx%.0f.png", source, platform, orientation, size.width * scaleFactor, size.height * scaleFactor];
// CONFIRMED: we have assembled the correct new image name.
viewBackground.frame = CGRectMake(0, 0, size.width * scaleFactor, size.height * scaleFactor);
viewBackground.autoresizesSubviews = YES;
viewBackground.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageViewBackground.autoresizesSubviews = YES;
imageViewBackground.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageViewBackground.image = [UIImage imageNamed:filename];
}
The problem: The correct image appears on the screen, but as as mentioned above, it still has the portrait dimensions. I'm certain the image changes as the artwork is significantly different, with elements being stacked horizontally versus vertically. But the new picture is cut off horizontally in landscape mode.
I have tried putting all sorts of wild values into newRect, and none of them make any difference. The image never actually moves, even if I radically change the origin in newRect. so my current theory is that my changes to the view sizes are being ignored/over written.
The Question: What am I missing that's preventing the resizing of the image to landscape mode? Is there some other auto sizing aspect I'm not addressing?
So, the problem turned out to be yet another variable in the saga. There also must be a constraint on the UIImageView that is 0 on each side, with "Constrain to Margins unchecked." Apparently, when I did that step earlier, it didn't actually take.
I have to admit, though, I really don't understand what that constraint is doing for me. It clearly makes the rotation work, but I don't get why. Since that's technically the answer to my original question, I'll gladly award the answer if someone can explain how this constraint enables this scenario.
EDIT:
In case anyone stumbles upon this answer in the future... I see now that setting the aforementioned constraint with all 0 buffers between the UIImageView and the UIView pins the edges of UIImageView to the edges of the UIView. When the device rotates, the viewController resizes the UIView, and with this constraint, the UIImageView resizes also. I was able to remove the majority of my code. The only code I need is to select a portrait or landscape image, and I was able to remove everything that resized the UIView and UIImageView.
The image now changes size properly when rotating just by using the one constraint. I only need code to decide whether to show a landscape or portrait background. (And I vastly simplified that code by storing my images in an asset catalog so the code just selects the name of "portrait" or "landscape", but the size of the image is auto selected based on the device).

Dealing with 3.5 and 4 inch screen, is there a way to see what the screen size is? [duplicate]

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

How to prepare my iOS app for the new iPhone 5 size? [duplicate]

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

Why is my ModalView displaying in portrait mode?

Hopefully somebody can point out what I'm doing wrong with my Splash screen here. The problem is that the screen is displaying in portrait mode, not landscape...
- (void)showSplash
{
UIView *modelView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024 , 748)];
UIViewController *modalViewController = [[UIViewController alloc] init];
[modelView setBackgroundColor:[[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"Splash.png"]]];
modalViewController.view = modelView;
[self presentModalViewController:modalViewController animated:NO];
[self performSelector:#selector(hideSplash) withObject:nil afterDelay:5.0];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
Thanks in advance for the help.
Looks like you are writing app for iPad. If so, you have to support both landscape as well as portrait orientation otherwise Apple will reject it. I would suggest that you should use two different images. Image specifications are as follows:
Default-Landscape.png (1004 * 768)
Default-Portrait.png (748*1024)
(I am assuming that you are showing status bar if not add 20 pixels to height of an image)
That's it, create these images and add it to your project. And you are good to go. No Need to write any additional piece of code too..
And ya make it
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
You shouldn't rely on a function in your code to display the splash screen. Just define them as the previous answer from Sumit Lonkar explains.
If you do it in code, I believe at the start of the application the orientation is always considered as portrait, then the transition to the actual orientation is triggered. This explains why your code displays first as portrait and most likely there is nothing else in the code to handle rotation. Besides, the purpose of the splash screen is to display something while the app is loading, so if you put it in code you lose the purpose.
By doing it the Apple way you leave it to another Apple process that runs before looking at your code and it will work.
Regarding the orientation supported I have on my iPad some apps that support only landscape (TapZoo for example) so it should be ok with Apple.

Resources