How to properly use a UINavigationController - ios

I just recently started programming for iOS/iPhone. I thought I knew what I was doing until XCode5/iOS7 came around. Previously, I created a class derived from UIViewController with a XIB, added a label, and programatically added it to the rootWindow:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
... // boilerplate code
MyViewController* myRoot = [[MyViewController alloc]init];
self.window.rootViewController = myRoot;
To use a navigation bar, I changed the code slightly:
MyViewController* myRoot = [[MyViewController alloc]init];
UINavigationController* navigationController = [[UINavigationController alloc]init];
[navigationController pushViewController:myRoot animated:YES];
self.window.rootViewController = navigationController;
This seemed to work fine. However, on iOS 7 the controls at the top of my custom view controller appear to be behind the navigation bar. Some googling resulted in this link which describes changes in the status bar.
It also seems to indicate that,
A) UINavigationController should handle the changes automatically
B) "auto layout" should handle the changes automatically,
and that I shouldn't need to worry. However, my sample app above doesn't appear to handle anything automatically.
I also found some other sample code which uses the controller differently: adding the navigation controller's view as a subView to an existing view. This sort of makes sense for adding a navigation controller later on in an app's lifetime, but I am trying to set one up on launch.
Am I using the UINavigationController correctly?
What do I need to consider for iOS7 vs. earlier versions?
How do I configure "Auto Layout" (I don't see this in interface builder anywhere)?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}

Related

Who is responsible for creating the window under the hook when using storyboards

if we are using storyboards to deliver the interface setting in out ios app, then the AppDelegate.m will be quite clean and the only thing we are caring about is making our logic code enter at the viewDidLoad() function in the viewController which we hooked with a storyboard.
And there is a way that wildly used when we choose not to load the storyboard and make our window ourself at Application didFinishLanchingWithOption method of AppDelegate.m like this:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *viewController = [[ViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
the document says there should be a window and a rootViewController for our app to present stuff on the screen.
But if we are using the storyboard, who did this stuff for us? I mean things like creating the window and assign the rootViewController?
And can we choose what kind of rootViewController when using storyboard?
And once a rootViewController is assigned, can we choose to replace that?
Mostly I am asking how did all the stuff organized under hook

How to remove storyboard from existing iPhone project

I am new to iPhone programming and now facing problem with storyboard. I want to remove storyboard from application and call view controller from appDelegate programmatically. How can I accomplish this?
Here is my code in appDelegate :
FirstViewController *firstView = [[FirstViewController alloc] init];
self.window.rootViewController = signInView;
return YES;
Still its showing black screen. Please help me. Thanks.
remove Main storyboard file base name. It's .plist.
The reason it's showing a black screen is because there is nothing configured in your FirstViewController class. Try setting firstView.view.backgroundColor = [UIColor greenColor]; right before the return YES' and you'll see that the FirstViewController is in fact loading; it just doesn't have any configuration besides what you've done in the init method of your FirstViewController class.
Honestly, configuring ViewControllers outside of the storyboard is not fun for beginners. I don't know why you want to do it, but your alternatives are using .nibs or adding everything manually. I encourage you not to delete your storyboard, but if you must, your code is fine. Just delete the storyboard file, or better yet, just don't use it until you decide to come back to it because it's a better idea.
Did you initialize the window and made it key?
Here is an implementation of one of my apps:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [[DDHDemoViewController alloc] init];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
Maybe you have to remove the Main Interface in your project settings.
Here are the steps how I am doing.
Create a Empty project or If you have already created no worries, just remove StoryBoard entry from plist as #trick suggested.
delete MainStoryBorad file from your project
Create New UIViewController with XIB file named "MyViewController"
In your AppDelegate.h add #property for New Controller "MyViewController"
In your AppDelegate.m update didFinishLaunchingWithOptions method this way.
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] ;
MyViewController *viewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
I think it is better to use storyboards than xib if your application is not that much complicated with large number of UI View Controllers.
If you want to remove storyboard from project and use nib to use with the development do the steps with this link:
http://www.wastedpotential.com/create-an-ios-app-without-storyboards-in-xcode-5/
Please find the below link and Check with things..
1. Info.plist or General Info -> Removing main Interface
2. Check with .xib connections -> Custom class is added, view connection in .xib
https://github.com/sunilhts/RemoveDefaultStoryBoard
Delete MainStoryBorad file from your project.
Delete MainStroryBoard Key from info.plist file.
Clear MainInterface option from Project setttings.
Create New UIViewController with XIB file named "MyViewController"
In your AppDelegate.h add #property for New Controller "MyViewController"
In your AppDelegate.m update didFinishLaunchingWithOptions method this way.
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] ;
MyViewController *viewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}

Switch between different Views with a Navigation Controller

I'm totally new to iOS programming. I only programmed on Android so far and Objective-C is a total different and new language for me now.
What I want to do is to not use a design that I've created with the storyboard. I want to do all programmatically, since I think it will be more dynamic if I do it like this.
The problem I'm encountering is, that I want to have 3 different views. I googled a bit, and stumbled upon some stackoverflow questions. There, people suggested using a NavigationController. Okay. Now I'm trying to implement it. What I want to have is the following
A MainViewController that has 3 different views. The first view is a loginView. The second one is displaying data and the third is displaying detailed data dependent on the click of the second view.
Is a navigationcontroller corerct for this? The problem I'm having is where I tell the app that I want to start with the MainViewController and push the LoginView in it.
I have a MainViewController.h and MainViewController.m that are subclasses of UIViewController
Now, where exactly do I do this? I have the didFinishLaunchingWithOptions method right here with the following content
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
UIViewController *viewController = [[MainViewController alloc]init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navigationController pushViewController:viewController animated:NO];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
But that just crashes the app. What am I doing wrong? How do I get those three views? Am I starting completely wrong? Please help. As I said I'm new to iOS development. It's easy for me to programm on one view. I did that already, but I want thre different views! Thanks!
A MainViewController that has 3 different views. The first view is a loginView. The second one is displaying data and the third is displaying detailed data dependent on the click of the second view.
That's wrong.
You need three different view controllers, each of those will manage its own view.
Then you push one after another in the navigation controller, depending on user interaction.
Yes, Gonzalo Aune is rite, You should not push the rootviewcontroller in NavicationController.
Also , I will Suggest you to keep your first view (Login View) out of Navigation controller.
You can start with your MainViewController and based on check and conditions you can present LoginView on MainViewController using
[self presentViewController:loginViewController animated:YES completion:NULL];
And after successful login you can dismiss LoginViewController.
Remove this:
[navigationController pushViewController:viewController animated:NO];
You shouldnt push the ViewController since you told the NavigationController already that the ViewController would be the root one:
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:viewController];
use this code and if application is universion then use same code else remove the condition of ([[UIDevice currentDevice] userInterfaceIdiom]
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navController;
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];
{
if(result.length>0)
{
for(var i in result)
{
var ObjResult=result[i];
var content = "<div data-role='collapsible' id='set" + i + "'>";
content+="<h3>"+ObjResult.title+"<br>";
var intDate=parseInt(ObjResult['ordered date']);
content +=timestampToDate(intDate)+"</h3>"
if(isNaN(ObjResult.med_placeorderfor))
content+="<p><a>Medicle Place order for: </a>"+result[i].med_placeorderfor+"</p>";
if(isNaN(ObjResult.pres_placeorderfor)>0)
content+="<p><a>Medicle Place order for: </a>"+result[i].placeorderfor+"</p>";
if(ObjResult['order status'].length>0)
content+="<p><a>Order status: </a>"+ObjResult['order status']+"</p>";
if(ObjResult.comments.length>0)
content+="<p><a>Comments: </a>"+ObjResult.comments+"</p>";
content+="</div>";
}
$("#id_notification_list_dashboard").append( content ).collapsibleset('refresh');
$("#id_notification_list_dashboard").trigger('create');
}
else
{
$("#id_notification_list_dashboard").append("<div style=\"text-align:center\" data-role='list-divider'><h1>No data found</h1></div>").collapsibleset('refresh');
}
$('body').removeClass('ui-loading');
loadingWithMsg("hide");
}
} else {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
navController=[[UINavigationController alloc]initWithRootViewController:self.viewController];
[navController.navigationBar setTranslucent:YES];
navController.navigationBar.tintColor = [UIColor colorWithRed:161.0f/255.0f green:18.0f/255.0f blue:6.0f/255.0f alpha:1];
self.window.rootViewController =navController ;
[self.window makeKeyAndVisible];
return YES;
}

Tabbed application won't show Login view

I have a tab bar application in Xcode 4.3 and I'm trying to insert a login screen before the tabbar is shown. The app works OK if presentModalViewController has animated:YESbut if it is without animation the view is not showing.
#synthesize window = _window;
#synthesize tabBarController = _tabBarController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
LogInViewController *logViewController = [[LogInViewController alloc] initWithNibName:#"LogInViewController" bundle:nil];
[self.window addSubview:_tabBarController.view];
[self.tabBarController presentModalViewController:logViewController animated:YES];
//This wont work
//[self.tabBarController presentModalViewController:logViewController animated:NO];
[self.window makeKeyAndVisible];
return YES;
}
-(void)loginDone{
NSLog(#"back to the app delegate");
[self.tabBarController dismissModalViewControllerAnimated:YES];
}
Is this the right way to do it?
Why wont the code work with animated:NO ?
I also get this on output Unbalanced calls to begin/end appearance transitions for <UITabBarController: 0x689d350>.
First of all, move [self.window makeKeyAndVisible]; before your view controller setup.
Additionally, you should be presenting the modal view controller within the viewWillAppear: method of the view controller that will be visible first, to make sure your apps view hierarchy has been fully initialized before presenting your login screen.
Don't do this:
[self.window addSubview:_tabBarController.view];
Do this:
self.window.rootViewController = _tabBarController;
This will put the tabBarController on the screen. But that's not exactly what you want... My advise is:
1) Start by putting the logViewController has the rootViewController as I showed you above.
2) Once you got what you want (login is successful) just tell the AppDelegate to switch the rootViewController. This can be done in with delegation or notifications.
Also, as Toastor indirectly pointed out, you should start the presentViewController from the UIViewController who actually initiates it (and not from the AppDelegate).

Converting a simple app to have a tab bar

I have a question that is similar to this SO question, but slightly different (or my skills don't allow me to follow the directions with confidence). I have an existing game app that has one view controller and one nib and works fine. I want to convert it to have a tab bar controller. I want the original, existing view controller to be on the first tab, and I wrote a new view controller and a new nib for the second tab, which will be dedicated to game settings. At this stage, the app builds and runs fine with the new nib and view controllers in the project (but with no further edits -- no attempt to add the tab bar controller etc). The modified app should simply have two views each accessible from one of the two tabs.
Sorry for the long bkgnd. I'm following the accepted answer to the above-referenced question. The first 4 steps I have done or can do. The 5th step is to Delete the old version of your Main View Controller from the NIB file and also remove the IBOutlet property from the Application Delegate. I don't think I have such an IBOutlet in my app (which is different from the OP's app). Should I delete the object view controller shown in this list? Or am I on the wrong track here?
Additional Info
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Set up view controller & load a clean view
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[P3ViewController alloc] initWithNibName:#"P3ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
NSLog(#"P3ViewController now active");
[self.window makeKeyAndVisible];
return YES;
}
This should get you in the right direction...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UITabBarController *tbc = [[UITabBarController alloc] init];
YourNewViewController *ynvc = [[YourNewViewController alloc] initWithNibName:#"YourNewViewController" bundle:nil];
YourCurrentViewController *ycvc = [[YourCurrentViewController alloc] initWithNibName:#"YourCurrentViewController" bundle:nil];
[tbc setViewControllers:[NSArray arrayWithObjects:ynvc, ycvc, nil]];
self.window.rootViewController = tbc;
[self.window makeKeyAndVisible];
return YES;
}

Resources