In my storyboard for a container class, I have created a full-screen Container View with an embed segue that's attached to a UINavigationController. I'm trying to test this by pushing a viewController programmatically like below:
UIViewController* test = [[UIViewController alloc] init];
test.view.backgroundColor = [UIColor redColor];
UINavigationController* navC = [[RootController mainStoryBoard] instantiateViewControllerWithIdentifier:#"containerNav"];
[navC pushViewController:test animated:NO];
navC is successfully initialized as the navigation controller, but the pushViewController call seems to do nothing. I still just see an empty navigation controller on the screen (default navigation bar with black view). I also tried a similar test with the setViewControllers method, which also failed. Are navigation controllers not meant to be embedded into container views?
UINavigationController needs a UIViewController at the bottom of its stack from when it is first created, (and it can't 'pop' that one). In other words it can't begin with an empty stack, you should be adding/embedding one viewController inside it in the xib/storyboard, then I expect it'll work with what you're doing here
I think you may need to just set the viewControllers property on the Nav Controller, like this:
[navC setViewControllers(#[test] animated: NO]
Related
I have 3 VC(view controller) (VC1, VC2, VC3).
At VC1, I used the code:
self.navViewController = [[UINavigationController alloc] initWithRootViewController:viewController];
self.navViewController.view.frame = CGRectMake(self.view.frame.size.width - viewController.view.frame.size.width,
viewController.view.frame.origin.y,
viewController.view.frame.size.width,
viewController.view.frame.size.height);
[self.navigationController addChildViewController:self.navViewController];
[self.navigationController.view addSubview:self.navViewController.view];
[self.navViewController didMoveToParentViewController:self.navigationController];
The VC2 is showing, and then at VC2 I used the code to push navigation controller to VC3
VC3 *vc3 = [[VC3 alloc] initWithNibName:#"VC3" bundle:nil];
[vc3.view updateConstraintsIfNeeded];
[self.navigationController pushViewController:vc3 animated:YES];
Currently, when I'm adding snippet code [vc3.view updateConstraintsIfNeeded];. I saw navigation of changed and content view does not change and show. It just shows a content view of VC2.
In my project, I'm using auto layout. I tried remove auto layout on my project it works well. When I added auto layout it works wrong.
It just occurs on iOS 7, iOS 8 work well.
Please, help me to resolve the bug. Many thanks!
The problem is you are displaying your VC2 on top of the pushed view controller. What is the reason to have one view controller as a child of a navigation controller? Instead, have a common ancestor of both VC2 and the navigation controller, or put your VC2 somewhere else in the view hierarchy, not on top of of the navigation controller's view, which holds the entire navigation controller (including contained controllers in the push stack) view hierarchy.
In my app, I dynamically load a set of images, and when a user taps on an image, it opens up a new ViewController (MediaPreview) that opens up a large preview of the image.
I create the MediaPreview controller as follows:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
mediaPreviewVC = (MediaPreviewViewController *)[storyboard instantiateViewControllerWithIdentifier:#"MediaPreviewViewController"];
mediaPreviewVC.selectedImageURL = [NSString stringWithFormat:#"%#",gestureRecognizer.view.tag];
navigationController = [[UINavigationController alloc] initWithRootViewController:mediaPreviewVC];
[self presentViewController:navigationController animated:YES completion:nil];
This creates a ViewController that looks like this:
However, the bottom navigation bar appears to be missing, which is outlined in my storyboard:
How can I ensure that the bottom navigation bar buttons appear in my view?
You are creating the navigation controller out of whole cloth:
navigationController = [[UINavigationController alloc] initWithRootViewController:mediaPreviewVC];
alloc-init means "make me a completely fresh, separate, generic one". Thus, navigationController is not the navigation controller in your storyboard. It's a completely new and different navigation controller. Thus, what's in your storyboard is irrelevant.
If you wanted the navigation controller from your storyboard, you needed to instantiate the navigation controller from the storyboard. Or, if you're doing this intentionally, then the bottom bar won't be visible unless you explicitly make it visible, because by default it isn't (it's obvious how to make it visible explicitly).
But then in that case, if you meant to pull it out of the storyboard, then your whole code is probably wrong, because the one in the storyboard probably already has the correct root view controller as well.
I'm using the ECSlidingViewController for my navigation menu, whenever I want to push a UIViewController from this menu, the UINavigationController of the pushed UIViewController is always nil.
The UINavigationController is initialized, the NSLog output shows the following <UINavigationController: 0x8a80770> address. When I call the method pushViewController:animated the UIViewController gets pushed but the UINavigationController is nil, therefore I can't see the UINavigationBar in this controller.
Here is the code snippet I'm using for this:
RecommendationsViewController *rvc = [self.storyboard instantiateViewControllerWithIdentifier:#"RecommendationsViewController"];
[self.transitionsNavigationController pushViewController:rvc animated:NO];
self.slidingViewController.topViewController = rvc;
In viewDidLoad the transitionNavigationController get's initialized with (please note the slidingViewController is from the ECSlidingViewController project on github https://github.com/ECSlidingViewController/ECSlidingViewController and is of type ECSlidingViewController):
self.transitionsNavigationController = (UINavigationController *)self.slidingViewController.topViewController;
Thanks for any help!
I think you have misunderstood how this is suppose to work.
The UINavigationController has to be the topViewController.
Don't reassign the topViewController after you do a push. By doing this:
self.slidingViewController.topViewController = rvc;
All that is going to do is set the current window to display that UIViewController, thats why you didn't see the nav bar, the app needs to display the UINavigationController which in turn will manage a list of UIViewController's
The navigation controller handles a stack of viewControllers, just push the new UIViewController and nothing else
There is a related issue where a Navigation controller's topViewController will forget that it is attached to a navigationController.
My Storyboard setup is: ->NavigationController->ViewController
The connection between NavController and ViewController is "root view controller".
I have set a storyboardID for each of these view controllers.
I have a view management class "ViewManager" that contains weak references to all storyboard views, which I obtain using:
_rootNC = [self.mainStoryboard instantiateViewControllerWithIdentifier:#"NavController"];
//ViewController gets auto-attached to the NavController, and so viewController.navigationController == NavController
_firstVC = [self.mainStoryboard instantiateViewControllerWithIdentifier:#"ViewController"];
//Instantiating the ViewController again clears its navigationController property, and so viewController.navigationController == nil
I suppose one shouldn't gain a hook into Storyboard Instances by reinstantiating the views. I'd appreciate if others would share their best-practices for obtaining weak references to storyboard viewControllers in such a way that I could control them in a single viewManager class. (I'm leaning toward setting viewManager.rootNC from within NavigationController's viewDidLoad).
I have a tab bar controller with 4 tabs and each tab is their own UINavigationController, which is how you're supposed to nest tab bar and navigation controller's together. The initial tab is a TableViewController and works/appears the way that it should. From the tableVC I can push standard view controller's onto the navigation controller with:
[self.navigationController pushViewController:VC animated:YES];
and it works properly.
If I attempt to push another TableViewController onto the navigation with the same method it works the same way, but the initial tab bar does not get pushed off screen like it should, it just stays in place.
Why would the tab bar stay on screen even though I am pushing a new VC onto the navigation?
I have tested with multiple instances of different TableVC's and it only happens with a table view controller.
Here is the code I'm using:
- (void)pushTableVC
{
TestTableVC *tableVC = [[TestTableVC alloc] init];
[self.navigationController pushViewController:tableVC animated:YES];
}
This will push the new table view onto the stack, but the tab bar from the parent VC stays in place and does not get pushed off screen like it should.
You should call the method setHidesBottomBarWhenPushed: on the view controller you are pushing to correctly hide the tab bar.
UIViewController *viewController = [[UIViewController alloc] init];
[viewController setHidesBottomBarWhenPushed:YES];
[[self navigationController] pushViewController:viewController animated:YES];
When you use a UITabBarController, the tab bar always stays on screen, even as you push additional view controllers onto an embedded UINavigationController. You will see this in any app that has a UITabBarController implemented, unless they implement custom behavior to change this.
The UINavigationController contains everything above the UITabBar, but does not contain the UITabBar itself, so it would not be able to push it offscreen.
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.