I'm adding navigation to subviews in my app from the home view.
I understand the concepts of pushing and popping view in the navigation stack, however, I don't want the navigation bar in the home screen.
Basically, when the user leaves the home view to any sub view, I'd like them to see the "Home" button on the left of the button nav bar, but no nav bar in the home view.
Any help would be appreciated.
It sounds like you want to start out with a bare UIViewController, containing your home screen with your own custom buttons.
The UINavigationController should come into play only when a user performs some action. Do this by
[navVC setModalTransitionStyle:UIModalTransitionStyleCrossDissolve]; // pick an effect
[self.viewController presentModalViewController:VC animated:YES];
Where navVC is the navigation controller, and self.viewController refers to your (new) main view controller. (add a suitable line IBOutlet UIViewController *viewController; + #property line + #synthesize line)
You need to fiddle a bit in the way the app starts up, for now it will probably show the navigation controller directly. If you are using a xib, you can do this by adding a UIViewController while leaving the navigation controller there as it stands. In application: didFinishLaunchingWithOptions: you'll find a line saying
[window addSubview:...];
which actually determines which viewcontroller's view is first visible. Change this to:
[window addSubview:self.viewController.view];
If you've done all this correctly, you've inserted the extra UIViewController between startup and navigation.
Related
I have a UIScrollView that houses three UIViewControllers so that I can swipe between them like the view setup in SnapChat.
In my ViewController on the very right of the UIScrollView I want the user to be able to select things and then navigate to a new page. So essentially I want the right-most UIViewController to be a Navigation Controller with a nav bar and and View Controllers I navigate to from this page should also have a nav bar and a Back button as the UIBarButtonItem in the top left as standard.
I went about it the normal way, just taking the View Controller and selecting "Embed In Navigation Controller" and looking at the storyboard it looks right, but if I run it, there's no nav bar at the top of the view controller.
I have the nav bar visibility set to "Show Navigation Bar" but still nothing.
Any help appreciated
Edit
The issue is more than likely to do with how I add the view controller to the UIScrollView which is as follows:
let settingsStoryboard = UIStoryboard(name: "SettingsView", bundle: nil)
let settingsViewController = settingsStoryboard.instantiateViewController(withIdentifier: "SettingsViewController")
self.addChildViewController(settingsViewController)
self.scrollView!.addSubview(settingsViewController.view)
So I'm only adding the view. So how would I add it as a Navigation Controller? Or can that be done?
The Problem you are facing is that you are adding your view controller directly inside the scroll view but you should add the navigation controller inside the ScrollView.
So go to story board create a StoryboardID for that navigationController which is attached to SettingsViewController and then replace the SettingViewController ID with your navigationController's Storyboard ID.
maybe use addChildViewController
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(5_0);
I have a sequence of views that are pushed on top of each other on a Navigation Controller. I would like to do two things with these views:
To open the Rear menu view from all of them;
To be able to navigate
back the stack using Unwind segues.
I found out that if I push view controllers on top of each other using regular push segues then the unwind segue works as expected, but then the self.revealViewController on each view controller is not set and the Menu can't be called using the revealToggle: selector.
If I change the push segues to subclasses of SWRevealViewControllerSeguePushController then the views are pushed on top of each other and the Menu can be called from any of them using the revealToggle. Unfortunately, the unwind segues stop working (I think this might be because the view controllers are stacked using addChild instead of pushViewController on the SWRevealViewController class).
Is there a way of working together with SWRevealViewController and Unwind Segues?
Below there is an example storyboard:
The first view controller is the navigation controller; the second is the SWRevealViewController; the three view controllers below navigate one to each other, and the third has an unwind segue to the first. The first and third controllers have buttons that open the menu.
As I stated before, if the segues between the bottom view controllers are regular push segues then the unwind segue works as expected; the menu button from the first view controller works (as it is connected directly to the SWRevealViewController), but the menu button from the third view controller doesn't.
Switching the segue types to SWRevealViewControllerSeguePushController makes the menu buttons from the first and third view controllers work correctly, but the unwind segue stops working.
Oh, and I tested using "popToRootViewControllerAnimated:" and it also doesn't work if the segues are set to SWRevealViewControllerSeguePushController.
I posted this question on SWRevealViewControllers github site and received an answer from Patrick Bodet who was EXTREMELY helpful. I will post the answer below so it may help somebody in the same situation as I.
I had to update the storyboard and added an additional navigation controller as shown below.
As shown in the figure, I wanted to be able to push view controllers on top of each other and also to unwind the segues both to the Login screen (from the Menu) and from stacked view controllers.
On my previous attempts, it seemed as if SWRevealViewController wasn't able to cope with proper navigation segues. Patrick's first suggestion was to move the original navigation controller from before the RevealViewController to before the First view controller. That actually worked, by I still needed to be able to unwind segue from the Menu to the Login screen, so I needed an additional navigation controller.
As suggested by Patrick, I added an additional Navigation Controller. And embarrassingly at the end I realised the button that pointed from the third to the first view controller had both an ibaction and a segue to the first, so that was why it was acting all weird! :-(
So, for the storyboard shown above, in order to work you just use regular Push segues for the view controllers. No need to use SWRevealViewControllerSeguePushController segues.
The code for First and Third view controllers is like this:
#import "ThirdViewController.h"
#import "SWRevealViewController.h"
#import "FirstViewController.h"
#interface ThirdViewController ()
#property (weak, nonatomic) IBOutlet UIBarButtonItem *menuButton;
#end
#implementation ThirdViewController
- (void)viewDidLoad {
[super viewDidLoad];
SWRevealViewController *revealViewController = self.revealViewController;
if (revealViewController) {
[self.menuButton setTarget: revealViewController];
[self.menuButton setAction: #selector( revealToggle: )];
}
}
- (IBAction)returnToFirst:(id)sender {
[self performSegueWithIdentifier:#"First" sender:self];
//[self.navigationController popToRootViewControllerAnimated:YES];
}
#end
I created a new navigation controller in my storyboard (not programmatically!) and set it to be "Root View Controller" to a regular UIViewController and added a button in it which says- forward to the next view controller (this second view controller is a view controller which I want that will have a back button to link to the initial view controller).
Now, whenever I try to link the button to the next view controller- "Pushing a navigation controller is not supported".
Help me please, and thanks
EDIT:
I accidentally subclassed UINavigationController, and not UIViewController in my class.
Thank you anyway.
I've tried this and have no problems, its all done in IB with no additional code required ...
Start a new project, "Single View Application" using story boards
Select storyboard and delete the views its produced.
Drag on a new Navigation Controller (it will bring a table view with it)
Delete the table and the table view controller, so you are just left with the Navigation Controller
Drag on a normal view controller
Right Click and drag from the Navigation controller to the new View and choose "Relationship - Root View Controller"
Drag a "Bar Button Item" on to the Navbar which should be visible on the top of your ViewController, you can rename this Forward if you wish.
Now drag on another view controller which is the one your "Forward" button will push in to view.
Right Click and drag from the bar button to the 2nd View Controller, and choose "Push"
Run the project and you will get a Single view with a Navbar and your button, clicking your button will Push the other view and give you a Back Button to return to the first View Controller. I'll try and post a picture of my storyboard if it helps.
Plasma
I had the same trouble. I wanted to have a navigation controller on each storyboard, so that each could run independently, be individually debugged, and so that the look would be right with the navigation bar.
Using other approaches, I found the UINavigationController would be retained from the original storyboard -- which I didn't want -- or I'd get errors.
Using the AppDelegate in your view controller to set the rootViewController worked for me (borrowing segue naming conventions from Segue to another storyboard?):
- (void)showStartupNavigationController {
NSLog(#"-- Loading storyboard --");
//Get the storyboard from the main bundle.
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Startup" bundle:nil];
//The navigation controller, not the view controller, is marked as the initial scene.
UINavigationController *theInitialViewController = [storyBoard instantiateInitialViewController];
NSLog(#"-- Loading storyboard -- Nav controller: %#", theInitialViewController);
//Remove the current navigation controller.
[self.navigationController.view removeFromSuperview];
UIWindow *window = [(AppDelegate *)[[UIApplication sharedApplication] delegate] window];
window.rootViewController = theInitialViewController;
To swap views Programatically you would need to select the segue and give it an Identifier like "PushView" then call it like this ....
[self performSegueWithIdentifier:#"PushView" sender:self];
That will programatically do the same as clicking the forward button. I've created you an example project with the code discussed above. Has an -(IBAction) with code in you can use for programatially changing the view.
PushView.zip
I also wanted to do this, present a screen (that had an embedded navigation controller) when the user pushes a button.
At my first attempt, I connected the segue from the button in the fist screen to the Navigation Controller, and the app was crashing with this error "Pushing a navigation controller is not supported".
This is the solution I found:
Select the segue from the button in the first screen to the navigation controller.
If it had an identifier, copy its name. Then delete that segue.
Then create a new segue by CTRL-clicking the button in the first view controller and dragging to the VIEW CONTROLLER YOU WANT TO PRESENT (not to the Navigation Controller that is pointing at it), and select Push in the small pop up window.
Then click the icon in the middle of the segue and paste the name you copied in the first step as an identifier for it.
IB is going to give you a warning "Scene is unreachable due to lack of entry points and does not have an identifier for runtime access via -instantiateViewControllerWithIdentifier:." Don't worry, it works perfectly.
If you want to customize the string that is shown as the Back button to return, you can add this line in the viewDidLoad method OF THE VIEW CONTROLLER THAT IS BEING SHOWED AFTER THE BUTTON IS PRESSED, that is the Child view controller.
(replace "Settings" with the name you need)
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.topItem.title = #"Settings";
...
}
I'm pushing a number of views:
the top one is a UITabBarController
the second one is a UINavigationController with a pushed view
the third one is a modal box.
Once the close button in the modalbox is pressed I'm trying to revert everything to the default state and change the tabbar index.
[self dismissModalViewControllerAnimated:YES];
[self.navigationController popViewControllerAnimated:NO];
[self.tabBarController setSelectedIndex:3];
This dismisses the modal view but doesn't do anything else. Any ideas what could be wrong? I read something about a possible ios bug but I don't know how to work around it.
Neither UITabBarController nor UINavigationController is a view. Both are subclasses of UIViewController and have a property NSArray *viewControllers.
If you have an actualView controlled by an ActualViewController that is pushed on top of a rootView controlled by a RootViewController that is the rootViewController for the navigationController, and you also have a modalView controlled by a ModalViewController, then put
[self dismissModalViewControllerAnimated:YES];
in ModalViewController.m, and put
[self.navigationController popViewControllerAnimated:NO];
in ActualViewController.m (from whence modalView is pushed, presumably), and put
[self.tabBarController setSelectedIndex:3];
in RootViewController.m (from whence actualView is pushed, presumably).
If modalViewController was never added to the navigationController, then it doesn't know that the navigationController exists.
If actualViewController was never added to the tabBarController, then it doesn't know that the tabBarController exists.
The easy (and dirty) way:
Dismiss the modal view in the modal view. Make the navigation view controller the delegate of the modal view. Make the tabbar controller the delegate of the navigation controller. When the button is pressed call a method in the navigation controller that pops the view and calls a method of the tabbar controller which changes the selected tab.
I have a "landing page/view" that I dont want the navigation bar to show, so I turn it off during the viewDidAppear
navigationBarHidden = YES;
When i push a view on the stack and then move it off. the main landing page shows the nav bar then hides it which cause a flicker that I dont want.
is there a way to have the landing page be a UIView or something? When a menu item is touched the app would push a new view on top of the default landing page. It sound like it would be hard to do without having the landing page be a UINavigationController. Any thoguhts?
Try hiding the navigation bar in viewWillAppear, rather than viewDidAppear.
If you don't need to go back to the landing page, use a view controller for the landing page and present it modally from the navigation controller when the application starts.
So you do want to go back to the landing page.
It's hard to accomplish that with UINavigationController. Suppose your are going back to the landing view. While the transition, the old view should have a navigation bar, and the new view (landing page) should not have a navigation bar. UINavigationController does not allow you manually modifying the transition animation. In other words, you cannot animate hiding/unhiding the navigation bar along with push/pop animation (using viewWillAppear doesn't solve the problem).
So what would I do, if I really, really need this?
I would have a rootViewController (of UIViewController), whose view is the only subview of your application window. When your application starts, rootViewController add the landing view as a subview of its view. When the user selects an item there, you create an UINavigationController with the corresponding view controller as its root view controller.
And, using CATransition animation with type of kCATransitionPush and subtype of kCATransitionFromRight, you add the view of the navigation controller as a subview of rootViewController's view.
Then you need a 'back' button for the first view of the navigation controller. In all view controllers that are the first level view controllers of the navigation controller, create a bar button item with a text 'Back', and add it to their navigationItem.leftBarButton property. Set a target-action (probably to the rootViewController) pair for the button.
When the action message fires, use CATransition animation (now with kCATransitionFromLeft subtype), to remove the current navigation controller's view from rootViewController's view.
The transition may not look as perfect as the native UINavigationController, but I believe this is the best you could get.
Actually the way to do this is to implement UINavigationController's delegate method navigationController:willShowViewController:animated. This method is where you should handle hiding and showing your navigation bar so the animation will occur during the push/pop animation.
I came across a method that is simple and works well for me, and is not given here yet. I assume you have a view controller for the main landing page and it is set as root view controller of the navigation controller. Then you should hide/show the navigation bar in the viewWillAppear and viewWillDisappear methods of the main landing page controller:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
Source:
http://www.iosdevnotes.com/2011/03/uinavigationcontroller-tutorial/