Initializing root view controller with myViewController / Using split view(sliding navigation) controller - ios

I'm working on adopting slide (split) view controller to my project.
JT, DD, ZUUI, JW, ECS.....
All these sources suggesting initialize my root view controller in appDelegate.
Something like this....
MyMainViewController *controller = [MyMainController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:Controller];
.........
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
Problem is I can't make my view visible, my app show blank page only with a empty navigation bar.
I customized my main view using AQGrid, is this causing a problem?
My view looks different to storyboard look. (because I customized it.)
So when I do initialize I'm using "self.storyboard initialize......method".
But in appdelegate, I can't use that method.
Simply, I can't make this view hierarchy because when I initialize my view it is not visible.
ZUUIRevealController is parent of:
UINavigationController is parent of:
FrontViewController

If you are using a storyboard, don't do any of that. Instead, choose your starting view controller from the storyboard and check the "Is Initial View Controller" in the Attributes inspector.

Related

Creating a UINavigationController for the first UIViewController

It seems there are several approaches to creating a UINavigationController to be the very first controller. Perhaps the easiest way is to simply click the View Controller in Storyboard and embed it in a navigation controller. But I would like to know the best approach when doing this only in code.
You can subclass UINavigationController, import the first view controller, and in viewDidLoad alloc and init an instance, then add it as a childViewController. In Storyboard replace the default view controller with a navigation controller and set the class to your nav controller. Note that in previous versions of iOS it was not recommended to subclass UINavigationController.
Or you can create another UIViewController, alloc init the first view controller, then alloc init a UINavigationController with that view controller as the root, add the navigation controller as a child view controller of this view controller, and add the navigation controller's view as a subview of this view controller's view. Change the class of the view controller in Storyboard. This is an awkward setup though, because you create a view controller whose purpose is to add a nav controller but it's not a nav controller itself.
I've read about another approach which involves creating the UINavigationController in the AppDelegate. Perhaps there are even more solutions.
What is the most appropriate approach, working in the latest development environment, targeting iOS 8+?
If you're starting with a controller in the storyboard, you only need to add two lines in the app delegate to embed that controller in a navigation controller. If you want to do it in code, I think this is the simplest way,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.window.rootViewController];
self.window.rootViewController = nav;
return YES;
}
If you want to do it entirely in code, with no storyboard, then you need to create the window, the navigation controller, and its root view controller. You also need to click on the project icon in the files list, and in the "General" tab, delete the word "main" from the "Main Interface" pull down (that entry tells the system to start with a storyboard named "main.storyboard").
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *vc = [ViewController new]; // You need to create this controller's view in its loadView method
vc.title = #"Root View Controller";
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
[self.window setRootViewController:nav];
[self.window makeKeyAndVisible];
return YES;
}

UINavigation pushing a new root controller

I am trying to push a new root controller to a navigation stack, but using a side reveal menu.
My app delegate has the following:
welcomeViewController = [[MyWelcomeViewController alloc] initWithNibName:#"MyWelcomeViewController" bundle:nil];
navController = [[UINavigationController alloc] initWithRootViewController:welcomeViewController];
navController.navigationBarHidden = YES;
// Then we setup the reveal side view controller with the root view controller as the navigation controller
self.revealSideViewController = [[PPRevealSideViewController alloc] initWithRootViewController:navController];
[self.revealSideViewController setDirectionsToShowBounce:PPRevealSideDirectionNone];
[self.revealSideViewController setPanInteractionsWhenClosed:PPRevealSideInteractionContentView | PPRevealSideInteractionNavigationBar];
// Then we make the window root view controller the reveal side view controller
self.window.rootViewController = self.revealSideViewController;
Once the welcome view controller is displayed, the user logs in. Once logged in the following process runs again from the App Delegate.
self.navController.navigationBarHidden = NO;
[self.navController setTitle:#"Home"];
[self.navController pushViewController:homeViewController animated:NO];
I then have a side view controller setup which is a table view with custom cells setup.
When a row is selected I need to push a new root controller onto the navigation controller. I try this by using the following in the table view for the cell selected.
MyAccountViewController *accountViewController = [[MyAccountViewController alloc] init];
[self.navigationController setViewControllers:[NSArray arrayWithObject:accountViewController] animated:NO];
Unfortunately this does not do anything. If I add the code to the App Delegate and then call the method from the table view controller then it works, however not from the .m file for the table view itself. Adding a log I can see the above is run, just does not do anything.
I am unsure if I need to do anything different on the above. For example, completely pop the views currently shown, then create the navigation controller and PPRevealSideViewController all over again. If I am supposed to, I am unsure how to pop all the current views to then push the new to the window, not from the AppDelegate.
The reason I do not want this in the App Delegate is because it is the incorrect way to approach this, and I would then need a separate method for each new root controller I would like to push from the menu, so the App Delegate would become very large.
Check UINavigationController.h:
#interface UIViewController (UINavigationControllerItem)
#property(nonatomic,readonly,retain) UINavigationController *navigationController; // If this view controller has been pushed onto a navigation controller, return it.
It means when you do myViewController.navigationController you will either get nil if myViewController is not pushed to any navController or the navController reference myViewController is pushed into.
As I understand your tableViewController is not pushed into the navController stack, that means you can't get the navController with tableViewController.navigationController. Instead you'll need to use anyViewControllerInTheStack.navigationController or if the navController is the rootViewController of your keyWindow, by
((UINavigationController*)[[UIApplication sharedApplication] keyWindow].rootViewController)
Add something like this to your AppDelegate.h:
#define XAppDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])
Now you can access any iVar of AppDelegate from any .m file in your project.
MyAccountViewController *accountViewController = [[MyAccountViewController alloc] init];
[XAppDelegate.navController pushViewController:accountViewController animated:NO];
Make sure you add the correct imports.
One more thing: It's good to pop the login window from your navcontroller once you are done Logging in.
Hope this helps.

Setting up a UINavigation controller and various view loads

I have setup a UINavigation controller that uses the AppDelegate as the main point of contact.
I have different methods which run such as presentHomeViewController, presentLoginViewController, which push the different view controllers to the Navigation Controller.
App Delegate - didFinishLaunching
welcomeViewController = [[MyWelcomeViewController alloc] initWithNibName:#"MyWelcomeViewController" bundle:nil];
navController = [[UINavigationController alloc] initWithRootViewController:welcomeViewController];
navController.navigationBarHidden = YES;
self.revealSideViewController = [[PPRevealSideViewController alloc] initWithRootViewController:navController];
[self.revealSideViewController setDirectionsToShowBounce:PPRevealSideDirectionNone];
[self.revealSideViewController setPanInteractionsWhenClosed:PPRevealSideInteractionContentView | PPRevealSideInteractionNavigationBar];
self.window.rootViewController = self.revealSideViewController;
Is this the correct process for this?
- (void)presentHomeViewController {
// We start by dismissing the ModalViewConrtoller which is LoginViewController from the welcomeview
[self.welcomeViewController dismissModalViewControllerAnimated:YES];
// Check if the home view controller already exists if not create one
if (!self.homeViewController) {
NSLog(#"presentHomeViewController- Creating the Home View controller");
homeViewController = [[MyHomeViewController alloc] initWithNibName:#"MyHomeViewController" bundle:nil];
}
// Push the homeViewController onto the navController
NSLog(#"presentHomeViewController");
self.navController.navigationBarHidden = NO;
[self.navController setTitle:#"Home"];
[self.navController pushViewController:homeViewController animated:NO];
If I then add the following to a different class :
[self.navigationController pushViewController:accountViewController animated:NO];
No view is pushed to the stack, should I control all the movement within the AppDelegate as I have been doing, or is there betters way to approach this?
EDIT
Thanks for posting your code. So, to address your final question first, I don't recommend controlling your navigation stack from the app delegate. You should be controlling the stack from the view controllers that are the children of the navigation controller.
To that point, remember the hierarchy of view controllers: UINavigationController inherits from UIViewController, and UIViewController has properties defined for all the things you'd see in a navigation layout such navigation items and title. More importantly, it also has properties for its parent view controllers, the view controller that presented it, and its navigation controller. So, considering the hierarchy, your app delegate should only instantiate the navigation controller's root VC and the nav controller itself, and then subsequently set the nav controller's root VC.
From there, you should be pushing and popping other VCs from the VCs themselves. Remember, every VC has a property that's automatically set to point at the navigation controller it's a part of. That's why [self.navigationController pushViewController:] works. For instance, if I have a nav controller whose root VC is a UITableViewController, and tapping on one of the items in the table view pushed a new VC onto the stack, I would push that VC from the table VC and not from the nav controller class or the app delegate.
Sorry if that's confusing. Please let me know if that needs clarification and I'll give it my best. Otherwise, hopefully that gets you on the right track.

iOS: Adding navigation bar from XIB

I have been seeing this issue and resolving it by manually creating UINavigationController in the code. Could someone please tell me when I add Navigation Bar from XIB's Attribute Inspector -> Set Top bar to Black Navigation bar, it gets displayed in the XIB but when I run the program, it doesn't appear! I noticed that self.NavigationController was coming nil so I added UINavigationController in my XIB and assign NIB but still it's nil! What's wrong with this? Do I need any additional settings?
[EDIT1]
I tried adding it like below and it works but I want parent class to forward rotation and appearance events to child controller automatically. If I do following it won't send them because I am adding nvc as child and not marketsListViewController. So I thought I have to subclass UINavigationController. See EDIT2.
self.marketsListViewController = [[MarketsListViewController alloc] initWithNibName:#"MarketsListViewController" bundle:nil];
UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:self.marketsListViewController];
nvc.navigationBar.barStyle = UIBarStyleBlack;
[self.marketsListView addSubview:nvc.view];
[self addChildViewController:nvc];
[nvc didMoveToParentViewController:self];
[EDIT2]
I have subclassed marketsListViewController to UINavigationController and thought following will work but it doesn't. It just displays navigation bar, UITableView doesn't get displayed!
self.marketsListViewController = [[MarketsListViewController alloc] initWithNibName:#"MarketsListViewController" bundle:nil];
self.marketsListViewController.navigationBar.barStyle = UIBarStyleBlack;
[self.marketsListView addSubview:self.marketsListViewController.view];
[self addChildViewController:self.marketsListViewController];
[self.marketsListViewController didMoveToParentViewController:self];
[EDIT3]
I was wrong in Edit1 that children controller won't get rotation events when I add child as navigation controller's root controller. Parent still sends all the events automatically and that's what I want! :)
Could someone please tell me when I add Navigation Bar from XIB's
Attribute Inspector -> Set Top bar to Black Navigation bar, it gets
displayed in the XIB but when I run the program, it doesn't appear!
What you see in you .xib file is just there to help you get your layout right and get a good idea of what it'll look like. When you have an app that uses a navigation bar, the bar is almost always managed by a navigation view controller (UINavigationController). The view controllers that the navigation controller hosts don't worry about the nav bar -- their view hierarchies go in the space beneath the bar.
So, the right way to get a navigation bar in your app is almost certainly to use a navigation controller. If you only have one view controller, make that that the navigation controller's root view controller (note: the root view controller of the window will be the navigation view controller). You can change the appearance of the bar from your view controller by setting the navigation bar's style:
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
Update: In the code you posted, you're just creating a new navigation controller, but not doing anything with it. I alluded above the the fact that (in most cases) the navigation controller should be the window's root view controller. It's fine to create your navigation controller in code, but you'll usually do it in the app delegate, and once you create it you'll set it as the window's root view controller. Here's an example borrowed from a project made fresh from Xcode's master/detail template (sans storyboards):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
MasterViewController *masterViewController = [[MasterViewController alloc] initWithNibName:#"MMMasterViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
Note that after creating the window and the navigation controller, the code sets the nav controller as the window's root view controller.

navigation bar not showing with a programmatically made UINavigationController

I have a navigation controller named navController made programmatically in my modal view controller during its viewDidLoad:
self.navController = [[UINavigationController alloc] initWithRootViewController:self];
self.navController.view=self.view;
[self setView:self.navController.view];
But when i launch the modal view controller i dont see the navigation bar, just the standard view i made in IB. Whats wrong?
Your solution cannot work.
Suppose that you have your modal controller called ModalViewController. It's a simple UIViewController linked with a xib created interface.
Now, at some point you need to present ModalViewController modally. As you wrote in your specification, I think you want to use also a UINavigationController and control its navigation bar.
The code to do this could be the following, where presentModally could be a method that it's not contained in ModalViewController.
- (void)presentModally:(id)sender {
ModalViewController *modalController = [[ModalViewController alloc] initWithNibName:#"ModalView" bundle:nil];
// Create the navigation controller and present it.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:modalController];
[self presentViewController:navigationController animated:YES completion: nil];
}
Now, within viewDidLoad of your ModalViewController you have access to navigationController property. In this manner you can control navigationController behaviour. For example:
- (void)viewDidLoad
{
[super viewDidLoad];
// the code changes the title for the navigation bar associated with the UINavigationController
self.title = #"Set from ModalViewController";
}
Some notes
To understand how UINavigationController works read UINavigationController class reference
To understand how modal controllers work read Modal view controllers documentation
The code I provided is a simple example and only demonstrative (I've written by hand so check for syntax). You need to make attention to memory management and how to present modal controllers. In particular, as Apple documentation suggests, to present modal controllers you need to follow these steps:
Create the view controller you want to present.
Set the modalTransitionStyle property of the view controller to the desired value.
Assign a delegate object to the view controller. Typically the delegate is the presenting view controller. The delegate is used by the presented view controllers to notify the presenting view controller when it is ready to be dismissed. It may also communicate other information back to the delegate.
Call the presentViewController:animated:completion: method of the current view controller, passing in the view controller you want to present.
Trigger (when necessary) some action to dismiss the modal controller.
Hope it helps.

Resources