I am trying to build on this demo which contains both a MainWindow.xib and a ImageManipViewController.xib . But my app contains the following code in the AppDelegate.m and my app does not (yet?) contain a MainWindow.xib. Is it better/best for me to add 2 MainWindow.xib files (one for iPhone and one for iPad) too (that are called in my method, each calling its own xib file) or is are the MainWindow.xibs just extra?
(Btw, if it turns out that the answer is that the MainWindow.xibs are redundant, then can you say why it might have been used in the original demo? Was it likely just a result of the author simplifying the steps in creating the demo, for example?) I have not found a way to contact the author directly.
If there is a better approach to developing a "universal" app, please advise me.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[BSViewController alloc] initWithNibName:#"BSViewController_iPhone" bundle:nil];
} else {
self.viewController = [[BSViewController alloc] initWithNibName:#"BSViewController_iPad" bundle:nil];
}
self.window.rootViewController = self.viewController;
You can build your main window and its attached subviews (and even view controllers) either programmatically or by using a Xib file. The result is the same, but small demo projects often use Xib files in order to simplify the code and focus on the part that they want to show you.
Two Xibs, one for iPad and one for iPhone is perfectly fine because iPad apps are encouraged to use views that make the most of the iPad large screen; for this reason, keeping them as separate files is recommendable. Your model and controllers should be common to iPad and iPhone, though.
And about loading Xibs, if your project is targeting iOS 4.0 or newer, you can name your xib files "BSViewController~iphone.xib" and "BSViewController~ipad.xib" and avoid some conditionals in your code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[BSViewController alloc] initWithNibName:#"BSViewController" bundle:nil];
self.window.rootViewController = self.viewController;
}
Related
I am unable to set a specific Main interface for iPad, even though my app is universal. Xcode used to have separate tabs for the Deployment Info on iPhone and iPad but now they are they same. However my game is radically different on iPhone and iPad and I need to set separate storyboards for each interface.
Someone please help if you know the solution.
you could set the value in the Deployment Info -> Main Interface to an empty string and implement a custom logic in your AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIStoryboard *initialStoryboard;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
initialStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
} else {
initialStoryboard = [UIStoryboard storyboardWithName:#"Main_iPad" bundle:nil];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [initialStoryboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
return YES;
}
You need to use size classes for this. To select the correct size class, open your storyboard file, then click on this icon towards the bottom of the screen.
Clicking wAny hAny will allow you to change the size class type and set specific constraints for the different device types. You can read more information about size classes here
I have a pretty general question - but I can't find a straight answer anywhere! If someone knows, please enlighten me!
I wanted to know the plan for submitting to the App Store with the new iPhone 5 dimensions. I assume that we will all need to make new graphics and separate views for all our apps if we don't want them letter boxed on the new device? So my question is, am I going to just make a new view controller that targets just this device? If so - what do I put into this code to make that happen? (as you see I've done it with the iPad view)
AppDelegate.mm
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
} else {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Looking forward to finding out! Thanks!
Sean
You don't have to redo everything. That would be crazy. You just have to get the size of the screen or the main window instead of hardcoding a 480 point height. And set the autoresizing mask to have flexible height.
I have an app that was already in the app store and I wanted to update it for the new screen resolution. The simple answer is that I added a blank screenshot into the Retina 4-inch launch image. Once this was done, the app resized itself. My app is all table and web view with text and photo entry, so it resized beautifully.
I did try several things before discovering this, but I removed all other changes once I discovered that the Launch Image was the reason my app wasn't loading full screen.
I am developing a xib-based landscape-only app. The app launches in landscape correctly. However, the view in my main ViewController is presented in portrait. That is, it is rotated 90 degrees so that the image appears cropped and does not take up the entire screen. If I use my interface to present a modal view controller then return to the main ViewController, the issue corrects itself (the view is presented in landscape). This problem did not occur under Xcode 4.2. It occurred after upgrading to Xcode 4.3, and the only code changes that were made were automatically implemented by Xcode when I upgraded the project settings.
Based on advice in other posts, I verified my Info.plist settings for Supported Interface Orientations and Initial Interface Orientation. I overrode the shouldAutorotateToInterfaceOrientation method for each of my view controllers to return YES only for landscape orientations. Also, I turned off auto resizing for the view, as I never want the size/orientation of the view to change.
Based on the ideas in this link [1], I suspected the problem is that the view is not receiving the call to change orientation at launch, possibly due to the removal of the MainWindow.xib concept, which appears to be replaced by the following Xcode-inserted code in AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
I modified this method to generate a generic root view controller from which my ViewController class is presented, as shown in the code below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController* myViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.viewController = [[UIViewController alloc] init];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[self.viewController presentModalViewController:myViewController animated:NO];
return YES;
}
Voila! This solved my problem. However, to me it feels like a change at a fundamental level, which I don't want to make at this point in my development. What I intended to be my root view controller is now a modal view. Does anyone have another solution to this issue?
Thanks in advance!
I had this same issue: an app which was meant to be in Landscape that assumed the ViewController was always in Portrait. I made tons of changes to every aspect of the project and info.plist, including giving the main UIWindow a root-view controller which was landscape. It still didn't work. I eventually undid all the changes and just added the two lines noted below to my app delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[_window addSubview:[_viewController view]];
glView = _viewController.glView;
// THIS FIXED ORIENTATION FOR ME IN IOS 6
_window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// END
...my other setup code here...
}
Nothing else was necessary.
It appears that, for some reason, in iOS 6 the UIWindow root-view-controller setting is sometimes ignored in Interface Builder. I am sure my reasoning is wrong somewhere, but I thought this might well help prod someone in the direction of a fuller, more exhaustive answer.
In iOS 8, settings windows frame to the UIScreen is also necessary, as it won't get automatically updated.
self.window.frame = [UIScreen mainScreen].bounds;
I've set up a BOOL called isUsingiPad to detect when my user is using an iPad. I used this to do so:
UIDevice* userDevice = [UIDevice currentDevice];
if (userDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
isUsingiPad = YES;
}
When my application first starts, it checks to see if the device being used has gone through my registration. If it has then it sends the user to the main View Controller of my app. However... when a registered user (that is using an iPad) registers, closes the app, then re-opens it, they are sent to the iPhone nib instead of the iPad. I have 2 nibs for each view in my app. One for iPhone and one for iPad. There is a single View Controller controlling each set of 2. I have already put in place the code to handle whether it's an iPhone or an iPad. My question is this: What should I add to make sure that a user gets to the iPad nib every single time? Where do I add this? I can edit this question to include any code necessary. Thanks in advance.
Edit: Updated -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIDevice* userDevice = [UIDevice currentDevice];
if (userDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
isUsingiPad = YES;
}
if (!isUsingiPad) {
self.viewController= [[PassportAmericaViewController alloc] initWithNibName:#"PassportAmericaViewController" bundle:nil];
} else {
self.viewController = [[PassportAmericaViewController alloc] initWithNibName:#"PassportAmericaViewController-iPad" bundle:nil];
}
self.window.rootViewController = self.viewController;
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
This is what Apple uses in the app templates to achieve this, it is implemented in your AppDelegates applicationDidFinishLaunchingWithOptions:
Now making sure that your user is returned to the correct screen every single time, depending on your setup you may want to initialize this in viewDidLoad or viewDidAppear.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
} else {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
In order to dynamically load nibs for iPad/iPhone in universal applications you should use the following naming conventions:-
iPhone - MyNibName.xib
iPad - MyNibName~ipad.xib
Doing it this way you do not need to do any manual loading or if statements.
I am getting started with iOS programming, and created a new project in XCode 4.2.1. However, I do not see .xib file in my project as expected. I tried added a new .xib file and build interface on it, but when I run my program, I see a blank white screen on the iPad Simulator. Am I missing something? Thanks.
You can replace this method in the appDelegate (and the name of the xib / strip out universal aspects of code if needed)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil] autorelease];
} else {
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil] autorelease];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
or
choose a Single View Application from the templates you are offered when creating a new app