Multiple storyboards for different iPhone sizes - ios

I have the below code set up in appDel.m in didFinishLaunching.
I currently have 2 storyboards iPhone 5 and iPhone 6. The issues is the code I am using is not selecting the iPhone 5 storyboard, it always defaults to the iPhone 6.
UIStoryboard *storyBd;
CGSize result = [[UIScreen mainScreen]bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width, result.height * scale);
NSLog(#"The Result height is %f",result.height);
if (result.height == 1136) {
storyBd = [UIStoryboard storyboardWithName:#"i5Story" bundle:nil];
UIViewController *initView = [storyBd instantiateInitialViewController];
[self.window setRootViewController:initView];
}else if (result.height == 1334){
storyBd = [UIStoryboard storyboardWithName:#"i6Story" bundle:nil];
UIViewController *initView = [storyBd instantiateInitialViewController];
[self.window setRootViewController:initView];
}

Thats because the height isn't 1136 it is 568. You don't look for the retina height (1136), just the normal "1x" pixel size.
Also you really shouldn't do this, rather use auto layout and make one storyboard.

Related

Change status bar height, based on if the device is an iPhone X or not

In my application, I use a custom pod called MMDrawerController, to create a dummy status bar, unfortunately in the pod the status bar's height is always set to 20.
In order to fix this issue I have written the following code:
App delegate
MMDrawerController *mmdrawer = [[MMDrawerController alloc]init];
//UPDATE IPHONE X STATUS BAR
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height == 812.0f) {
NSLog(#"DEVICE NAME : iPhone X");
self.iphoneXHeight = -45.0;
self.iphoneXHeightPos = 45.0;
mmdrawer.height = 40;
}
else {
self.iphoneXHeight = -20.0;
self.iphoneXHeightPos = 20.0;
mmdrawer.height = 20;
}
}
MMDrawerController.h
#property (nonatomic,assign) CGFloat height;
MMDrawerController.m
_dummyStatusBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), self.height)];
Problem:
When I run my code the height property is always 0, would appreciate it if someone can point out what I am doing wrong here and how would I be able access the height property and modify it ?
Dont use fixed height for the status bar, you can get the height with this code:
UIApplication.sharedApplication.statusBarFrame.size.height
Change this line.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if (screenSize.height == 812.0f) {
NSLog(#"DEVICE NAME : iPhone X");
self.iphoneXHeight = -45.0;
self.iphoneXHeightPos = 45.0;
mmdrawer.height = 40;
}
With this one:
if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {
// determine screen size
int screenHeight = [UIScreen mainScreen].bounds.size.height;
switch (screenHeight) {
// iPhone 5s
case 568:
NSLog(#"iPhone 5 or 5S or 5C");
break;
// iPhone 6
case 667:
NSLog(#"iPhone 6/6S/7/8");
break;
// iPhone 6 Plus
case 736:
NSLog(#"iPhone 6+/6S+/7+/8+");
break;
// iPhone X
case 814:
NSLog(#"iPhone X");
break;
default:
// it's an iPad
printf("unknown");
}
}

Objective - C, what does [UIScreen mainScreen].bounds.size.width actually give and what does initWithSize: actually require?

I am writing a GUI, with a main menu, a second screen and a back button to the main menu. From the initial main menu I use the following lines of code:
midScreenX = [UIScreen mainScreen].bounds.size.width/2;
midScreenY = [UIScreen mainScreen].bounds.size.height/2;
WarScene *battle = [[WarScene alloc] initWithSize: CGSizeMake(midScreenX*2, midScreenY*2)];
SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
SKView * skView = (SKView *)self.view;
UIView *viewToRemove = [self.view viewWithTag:101];
[viewToRemove removeFromSuperview];
[skView presentScene:battle transition:reveal];
This works... I think. I open up a new scene, my second scene is the correct size and at least fills the screen. There is a node in that scene which is too big for the screen, and I am working on changing that, but I don't think that that would actually effect the UIScreen's bounds.
The problem arises when I return to the main menu with the following code:
midScreenX = [UIScreen mainScreen].bounds.size.width/2;
midScreenY = [UIScreen mainScreen].bounds.size.height/2;
GameScene *map = [[GameScene alloc] initWithSize: CGSizeMake(midScreenX*2 ,midScreenY*2)];
SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
SKView * skView = (SKView *)self.view;
UIView *viewToRemove = [self.view viewWithTag:3];
[viewToRemove removeFromSuperview];
[skView presentScene:map transition:reveal];
As far as I can work out, the values being passed through should be exactly the same as the values initially sent for [UIScreen mainScreen].bounds.size and yet the scene which is initialised is far too big.
Is there anything that I could be doing which might affect [UIScreen mainScreen].bounds.size? Or have I misunderstood what init and .bounds actually do?
In terms of what I have already done to try and solve this problem myself, I have looked at examples of how scenes are normally initialised. I see that often values are used in place of .bounds for example :
initWithSize: CGSizeMake(1024,768)
However, wouldn't that mean that on different devices the scene wouldn't be shown properly/fully?
if you are using iOS 6 or iOS 7,
both [UIScreen mainScreen].bounds.size.width and [UIScreen mainScreen].bounds.size.height is same in all orientation..
but in iOS 8 it give one value in landscape and give another value in portrait mode
NSLog(#"width %f",[[UIScreen mainScreen] bounds].size.width); //portrait ios7 or 6 = 320 , landscape ios7 or 6 = 320
NSLog(#"height %f",[[UIScreen mainScreen] bounds].size.height); //portrait ios7 or 6 = 568 , landscape ios7 or 6 = 568
NSLog(#"width %f",[[UIScreen mainScreen] bounds].size.width); //portrait ios8 = 320 , landscape ios8 = 568
NSLog(#"height %f",[[UIScreen mainScreen] bounds].size.height); //portrait ios8 = 568 , landscape ios8 = 320
so we can check conditions like this,
CGFloat midScreenX,midScreenY;
if (UIDeviceOrientationIsLandscape((UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation]))
{
//landscape mode
midScreenX = ([[UIScreen mainScreen]bounds].size.width>[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
midScreenY = ([[UIScreen mainScreen]bounds].size.width<[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
}
else
{
//portrait mode
midScreenX = [[UIScreen mainScreen]bounds].size.width/2;
midScreenY = [[UIScreen mainScreen]bounds].size.height/2;
}
I hope you warScene and gameScene are subclass of SKScene. The method initWithSize returns, A newly initialized scene object. and parameter 'size' is The size of the scene in points.
For more information refer https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKScene_Ref/index.html#//apple_ref/occ/instm/SKScene/initWithSize:

iPad2 is stay portrait for a second before move to landscape

We have an app-which is ONLY landscape, that works great on ALL apple devices .
It also has the launch images .
We are lost with this bug.
We have set the app for landscape only in the device orientation menu.
All views are positioning in code only.
What happens on iPad2(iOS7) ONLY , is when you switch between views, you see for a second a portrait mode (which looks bad because graphics is for landscape only-so image is on half screen) and than it switch back to the landscape back after a second.
For some other views , the iPad2 ONLY stay forever on portrait for some reason -that means we see the graphics on half screen .its not positioned right .
the size of the screen that we get is just fine
float width=[UIScreen mainScreen].bounds.size.width;
float height=[UIScreen mainScreen].bounds.size.height;
768/1024
**** views that made with storyboard are ok- the others that positioning made with software are bad.
I use the following code (based on link given in above comment):
BOOL OSIsBelowIOS8 = [[[UIDevice currentDevice] systemVersion] floatValue] < 8.0;
if(OSIsBelowIOS8) {
if( [ [ UIScreen mainScreen ] respondsToSelector: #selector( nativeBounds ) ] )
{
self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] nativeBounds]];
}
else
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}
} else {
self.window = [[UIWindow alloc] initWithFrame: [self screenBoundsOrientationDependent] ];
}
and this is my screenBoundsOrientationDependent
//Always return the iOS8 way - i.e. height is the real orientation dependent height
- (CGRect)screenBoundsOrientationDependent {
UIScreen *screen = [UIScreen mainScreen];
CGRect screenRect;
if (![screen respondsToSelector:#selector(fixedCoordinateSpace)] && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
screenRect = CGRectMake(screen.bounds.origin.x, screen.bounds.origin.y, screen.bounds.size.height, screen.bounds.size.width);
} else {
screenRect = screen.bounds;
}
return screenRect;
}

iOS iPhone Application running iOS7 Retina graphics for iPad2 and iPad Mini

I've noticed that the iPhone applications running on non-retina devices (iPad 2 and iPad Mini) are now by default rendered at iPhone Retina Graphics (2x) (If the Application has the retina assets).
Devices currently running iPhone Applications at Retina Graphics without a retina screen:
iPad 2
iPad Mini
There is now no Zoom option for non-retina devices running an iPhone application with retina graphics in the payload.
This is great however I've been trying to get my Openframeworks iOS environment to work with with the new retina window and it is still rendering a non-retina OpenGL window (as the device itself is not a high dpi 2x scale).
Environments:
openFrameworks 0.8 https://github.com/openframeworks/openFrameworks
Xcode 5.0.1
Target: iOS7
Current main.mm
ofAppiOSWindow * window = new ofAppiOSWindow();
NSInteger glViewW = [UIScreen mainScreen].bounds.size.height;
NSInteger glViewH = [UIScreen mainScreen].bounds.size.width;
// glViewW returns 768
// glViewH returns 1024
window->enableRendererES2();
// [UIScreen mainScreen] is used by enableRetina to check for scale dpi.
window->enableRetina();
window->enableDepthBuffer();
ofSetupOpenGL(ofPtr<ofAppBaseWindow>(window), 320, 480, OF_FULLSCREEN);
window->startAppWithDelegate("AppDelegate");
Main ViewController to run open (GameViewController.mm)
- (BOOL)createGLView {
if(self.glView != nil) {
return NO;
}
app = new GameEngineApp();
app->setDelegate(self);
NSInteger glViewW = [UIScreen mainScreen].bounds.size.height;
NSInteger glViewH = [UIScreen mainScreen].bounds.size.width;
// glViewW returns 320
// glViewH returns 480
CGRect glViewRect = CGRectMake(0, 0, glViewW, glViewH);
self.glView = [[[ofxiOSEAGLView alloc] initWithFrame:glViewRect
andApp:app] autorelease];
self.glView.delegate = self;
self.glView.multipleTouchEnabled = NO;
[appContainer insertSubview:self.glView atIndex:0];
[self.glView layoutSubviews];
[self.glView setup];
[self.glView startAnimation];
return YES;
}
Anyone have any idea? I'm working on a few solutions may have a fix soon.
Okay I found a solution before posting so going to put this up here for reference. :)
So when you create your main.mm, do not enable retina straight away. You need to wait until you have started the AppDelegate and let the native iOS core functions kick in.
So revised Main.mm:
#include "ofMain.h"
#include "ofAppiOSWindow.h"
int main() {
ofAppiOSWindow * window = new ofAppiOSWindow();
window->enableRendererES2();
//-------------------------------------------------------------------------
// --Disabled:-- window->enableRetina(); // delete / comment this line out here
//-------------------------------------------------------------------------
window->enableDepthBuffer();
// the below numbers will not effect the window size as this is done later
ofSetupOpenGL(ofPtr<ofAppBaseWindow>(window), 320,480, OF_FULLSCREEN);
window->startAppWithDelegate("AppDelegate");
}
Revised GameViewController.mm (where I am instantiating the openFrameworks glView):
- (BOOL)createGLView {
if(self.glView != nil) {
return NO;
}
app = new GameEngineApp();
app->setDelegate(self);
NSInteger glViewW = [UIScreen mainScreen].bounds.size.height;
NSInteger glViewH = [UIScreen mainScreen].bounds.size.width;
CGRect glViewRect = CGRectMake(0, 0, glViewW, glViewH);
//-------------------------------------------------------------------------
ofAppiOSWindow::getInstance()->enableRetina(); // <-- Enable retina here
//-------------------------------------------------------------------------
self.glView = [[[ofxiOSEAGLView alloc] initWithFrame:glViewRect
andApp:app] autorelease];
self.glView.delegate = self;
self.glView.multipleTouchEnabled = NO;
[appContainer insertSubview:self.glView atIndex:0];
[self.glView layoutSubviews];
[self.glView setup];
[self.glView startAnimation];
return YES;
}

in iPhone App How to detect the screen resolution of the device

In iPhone App,
while running the App on device How to detect the screen resolution of the device on which App is running?
CGRect screenBounds = [[UIScreen mainScreen] bounds];
That will give you the entire screen's resolution in points, so it would most typically be 320x480 for iPhones. Even though the iPhone4 has a much larger screen size iOS still gives back 320x480 instead of 640x960. This is mostly because of older applications breaking.
CGFloat screenScale = [[UIScreen mainScreen] scale];
This will give you the scale of the screen. For all devices that do not have Retina Displays this will return a 1.0f, while Retina Display devices will give a 2.0f and the iPhone 6 Plus (Retina HD) will give a 3.0f.
Now if you want to get the pixel width & height of the iOS device screen you just need to do one simple thing.
CGSize screenSize = CGSizeMake(screenBounds.size.width * screenScale, screenBounds.size.height * screenScale);
By multiplying by the screen's scale you get the actual pixel resolution.
A good read on the difference between points and pixels in iOS can be read here.
EDIT: (Version for Swift)
let screenBounds = UIScreen.main.bounds
let screenScale = UIScreen.main.scale
let screenSize = CGSize(width: screenBounds.size.width * screenScale, height: screenBounds.size.height * screenScale)
UIScreen class lets you find screen resolution in Points and Pixels.
Screen resolutions is measured in Points or Pixels. It should never be confused with screen size. A smaller screen size can have higher resolution.
UIScreen's 'bounds.width' return rectangular size in Points
UIScreen's 'nativeBounds.width' return rectangular size in Pixels.This value is detected as PPI ( Point per inch ). Shows the sharpness & clarity of the Image on a device.
You can use UIScreen class to detect all these values.
Swift3
// Normal Screen Bounds - Detect Screen size in Points.
let width = UIScreen.main.bounds.width
let height = UIScreen.main.bounds.height
print("\n width:\(width) \n height:\(height)")
// Native Bounds - Detect Screen size in Pixels.
let nWidth = UIScreen.main.nativeBounds.width
let nHeight = UIScreen.main.nativeBounds.height
print("\n Native Width:\(nWidth) \n Native Height:\(nHeight)")
Console
width:736.0
height:414.0
Native Width:1080.0
Native Height:1920.0
Swift 2.x
//Normal Bounds - Detect Screen size in Points.
let width = UIScreen.mainScreen.bounds.width
let height = UIScreen.mainScreen.bounds.height
// Native Bounds - Detect Screen size in Pixels.
let nWidth = UIScreen.mainScreen.nativeBounds.width
let nHeight = UIScreen.mainScreen.nativeBounds.height
ObjectiveC
// Normal Bounds - Detect Screen size in Points.
CGFloat *width = [UIScreen mainScreen].bounds.size.width;
CGFloat *height = [UIScreen mainScreen].bounds.size.height;
// Native Bounds - Detect Screen size in Pixels.
CGFloat *width = [UIScreen mainScreen].nativeBounds.size.width
CGFloat *height = [UIScreen mainScreen].nativeBounds.size.width
Use it in App Delegate: I am using storyboard
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
//----------------HERE WE SETUP FOR IPHONE 4/4s/iPod----------------------
if(iOSDeviceScreenSize.height == 480){
UIStoryboard *iPhone35Storyboard = [UIStoryboard storyboardWithName:#"iPhone" bundle:nil];
// Instantiate the initial view controller object from the storyboard
UIViewController *initialViewController = [iPhone35Storyboard instantiateInitialViewController];
// Instantiate a UIWindow object and initialize it with the screen size of the iOS device
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Set the initial view controller to be the root view controller of the window object
self.window.rootViewController = initialViewController;
// Set the window object to be the key window and show it
[self.window makeKeyAndVisible];
iphone=#"4";
NSLog(#"iPhone 4: %f", iOSDeviceScreenSize.height);
}
//----------------HERE WE SETUP FOR IPHONE 5----------------------
if(iOSDeviceScreenSize.height == 568){
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone4
UIStoryboard *iPhone4Storyboard = [UIStoryboard storyboardWithName:#"iPhone5" bundle:nil];
// Instantiate the initial view controller object from the storyboard
UIViewController *initialViewController = [iPhone4Storyboard instantiateInitialViewController];
// Instantiate a UIWindow object and initialize it with the screen size of the iOS device
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Set the initial view controller to be the root view controller of the window object
self.window.rootViewController = initialViewController;
// Set the window object to be the key window and show it
[self.window makeKeyAndVisible];
NSLog(#"iPhone 5: %f", iOSDeviceScreenSize.height);
iphone=#"5";
}
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// NSLog(#"wqweqe");
storyboard = [UIStoryboard storyboardWithName:#"iPad" bundle:nil];
}
return YES;
}
For iOS 8 we can just use this [UIScreen mainScreen].nativeBounds , like that:
- (NSInteger)resolutionX
{
return CGRectGetWidth([UIScreen mainScreen].nativeBounds);
}
- (NSInteger)resolutionY
{
return CGRectGetHeight([UIScreen mainScreen].nativeBounds);
}
See the UIScreen Reference: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIScreen_Class/Reference/UIScreen.html
if([[UIScreen mainScreen] respondsToSelector:NSSelectorFromString(#"scale")])
{
if ([[UIScreen mainScreen] scale] < 1.1)
NSLog(#"Standard Resolution Device");
if ([[UIScreen mainScreen] scale] > 1.9)
NSLog(#"High Resolution Device");
}
Use this code it will help for getting any type of device's screen resolution
[[UIScreen mainScreen] bounds].size.height
[[UIScreen mainScreen] bounds].size.width
If your goal is to get the model resolution type and not the resolution values themeselfs, this Swift solution might be helpful:
import UIKit
#objc(IphoneModelScreenSize)
public class IphoneModelScreenSize: NSObject {
// MARK: Enums
public enum IphoneModelScreenSize: Int {
case notAnIphone = 0,
twoThreeOrFour = 1,
se = 2,
sixSevenOrEight = 3,
plus = 4,
elevenXorXS = 5,
elevenProMaxOrXsMax = 6
}
// MARK: Class properties
public class func screenSize() -> IphoneModelScreenSize {
let bounds = UIScreen.main.bounds
let screenWidth = bounds.size.width
let screenHeight = bounds.size.height
switch (screenWidth, screenHeight) {
case (320.0, 480.0):
return .twoThreeOrFour
case (320.0, 568.0):
return .se
case (375.0, 667.0):
return .sixSevenOrEight
case (414.0, 736.0):
return .plus
case (375.0, 812.0):
return .elevenXorXS
case (414.0, 896.0):
return .elevenProMaxOrXsMax
default:
return .notAnIphone
}
}
public class func screenSizeStringValue() -> String {
return screenSizeEnumToString(screenSize())
}
// MARK: Private properties
private class func screenSizeEnumToString(_ screenSize: IphoneModelScreenSize) -> String {
var screenSizeAsString: String
switch screenSize {
case .notAnIphone:
screenSizeAsString = "Not an Iphone"
case .twoThreeOrFour:
screenSizeAsString = "2G, 3G, 3GS, 4 or 4s"
case .se:
screenSizeAsString = "5, 5s, 5c or SE"
case .sixSevenOrEight:
screenSizeAsString = "6, 6s, 7 or 8"
case .plus:
screenSizeAsString = "6+, 6s+, 7+ or 8+"
case .elevenXorXS:
screenSizeAsString = "11 Pro, X or Xs"
case .elevenProMaxOrXsMax:
screenSizeAsString = "11, Xr, 11 Pro Max or Xs Max"
}
return screenSizeAsString
}
}

Resources