SideNavigationController - Replace rootViewController of NavigationController - ios

I'm using the Material Framework by CosmicMind. Currently I'm trying to replace the ViewController once a row is selected in the SideNavigationController. Unfortunately I can't figure out how to do this. There're similar question here on StackOverflow (#1) unfortunately the solutions don't work for me.
Following my code in the AppDelegate.swift class:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myViewController = storyboard.instantiateViewControllerWithIdentifier("MyViewController")
let navigationController: NavigationController = AppNavigationController(rootViewController: myViewController)
let sideNavigationController: SideNavigationController = SideNavigationController(rootViewController: navigationController, leftViewController: AppLeftViewController())
// further code
return true
}
With this code everything works fine. The ViewController (MyViewController) is shown.
Now I'm trying to replace the MyViewController with MySecondViewController however this doesn't work. Following the code I've been using:
sideNavigationController?.transitionFromRootViewController(MySecondViewController())
The result is that the Toolbar disappears and I can't close the SideNavigationController anymore. So I've tried the following:
let navigationController: NavigationController = AppNavigationController(rootViewController: MySecondViewController())
sideNavigationController?.transitionFromRootViewController(navigationController)
With this code the Toolbar is visible once again but the problem with the SideNavigationController remains -> means: It can't be closed.
tl;dr
How do I replace the rootViewController of the NavigationController properly?

The NavigationController is a subclass of UINavigationController. So changing the rootViewController is as iOS made it. For example:
navigationController?.pushViewController(MySecondViewController(), animated: true)
The SideNavigationController offers the ability to transition its rootViewController. This is different, as the SideNavigationController uses child UIViewControllers and swaps them when asked. For example:
sideNavigationController?.transitionFromRootViewController(MySecondViewController())
Sometimes, people use the sideNavigationController to early. For example, you instantiate a new UIViewController, and place the sideNavigationController code in the videDidLoad method. This won't work since the new UIViewController was not yet added to the sideNavigationController view hierarchy. To solve this, use the viewWillAppear method.
The last situation to consider is when you want to load a new UIViewController in the rootViewController of the NavigationController from the sideNavigationController. In order to do this, and let's consider that the sideNavigationController's rootViewController is the NavigationController, you would need to do this:
(sideNavigationController?.rootViewController as? NavigationController)?.pushViewController(MySecondViewController(), animated: true)
This should help you out :)

Related

Present a UIViewController from an UINavigationController via App Delegate

I am building an iOS app in swift and upon launching the app I would like to first show viewController2, which is presented on top of viewController1, which is embedded in a UINavigationController. The key part being that ViewController2 is not part of the navigation stack and is presented instead of being pushed.
This is my current attempt which doesn't work and only shows ViewController1 upon launch.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController1 = mainStoryboard.instantiateViewController(withIdentifier: "VC1") as! ViewController1
let viewController2 = mainStoryboard.instantiateViewController(withIdentifier: "VC2") as! ViewController2
let navController = UINavigationController(rootViewController: viewController1)
viewController1.present(viewController2, animated: false)
self.window?.rootViewController = navController
self.window?.makeKeyAndVisible()
return true
}
I have this structure in place because I enable a user to be able to swipe from left to right and right to left to get to viewController2 and viewController3 in a similar fashion to Snapchat. Presenting these controllers seemed the best idea as they don't have navigation bars and once finished you would want to return to viewControlller1 - perhaps I need to change the structure of my app but would ideally not like to as I aim to submit this mvp within the next week.
Help much appreciated from you iOS and swift wizards.
// Think I need to change the structure of the app to include viewController2 on the navigation stack :( as using accepted answer causes viewController1 to be seen briefly before viewController2 is presented which is logical - in the long run this will be better despite the short term pain
rootViewController should be set before everything. Do it in this order and it should work fine.
self.window?.rootViewController = navController
self.window?.makeKeyAndVisible()
navController.present(viewController2, animated: false)

How can I change my initial View Controller when the user accepts the EULA

I hope this is a simple question. I have not found anything in SO that seems to fit what I'm trying to do. I am working on my first ever project so much of this is still quite new to me. The code I have pasted is from a test project I'm using before I add code to my real one.
My initial VC is the EULA. When the user accepts, I want to change the initial VC to the log in view. In this test project, I have two views with an IBAction for a Bar Button Item that will segue the project from VC to VC2. I am trying to set up code to change the initial VC in the AppDelegate with
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "View Controller", bundle: NSBundle.mainBundle())
let licenseAccepted = ?
var vc: UIViewController?
if !licenseAccepted {
vc = storyboard.instantiateViewControllerWithIdentifier("View Controller2")
} else {
vc = storyboard.instantiateInitialViewController()
}
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = vc
window?.makeKeyAndVisible()
return true
}
but this is not working. First, let licenseAccepted = ? is not correct. I found that in another set of code and I thought it might work, but no. Also, how do I set a var for if the user accepts the license in the AppDelegate? Should that be done in the initial VC, the second VC that will become the initial VC or somewhere else?
I am using Xcode 7.1 and Swift2 if that helps.
I may be way off base or I may be a keystroke or two away. I am just not getting my head around this. Your assistance will be appreciated.

Navigation Bar gone

How can I present a view controller from my AppDelegate and have a Navigation bar added to that view with a back button to the previous view? I need to do this programmatically from my AppDelegate. Currently I can push a controller from there, but it doesn't act like a segue. It doesn't add a nav bar with a back button. Now I know I should be able to add one myself, but when I do it gets hidden. Currently I'm using pushViewController(), but I imagine that's not the best way to do it.
I had something that I think is similar, if not the same:
HIGH LEVEL VIEW
The general composition of my App (thus far, and specific to the issue at hand - note: details about classes provided for context, not required for resolution) is as follows:
UIViewController (ViewController.swift) embedded in a UINavigationController
Buttons on UIViewController segue to a view with a custom class:
ExistingLocationViewController - subclass of:
UITableViewController
One of the buttons (Add New Location) in the UINavigationController's Toolbar segues to view with another custom class:
NewLocationViewController - subclass of:
UIViewController
CLLocationManagerDelegate
UITextFieldDelegate
There are a number of other items here, but I believe the above is sufficient as the foundation for the issue at hand
RESOLUTION
In order to preserve the navigation-bar (and tool-bar) going both forward and back - I have the following code in my custom classes (note: the following is Swift-3 code, you may have to adjust for Swift-2):
override func viewDidLoad() {
super.viewDidLoad()
//...
navigationController?.isNavigationBarHidden = false
navigationController?.isToolbarHidden = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated) // #=# not sure if this is needed
navigationController?.isNavigationBarHidden = false
navigationController?.isToolbarHidden = false
}
You could actually omit the last two lines in viewWillDisappear, or perhaps even omit the entire override function
The net result (for me) was as depicted below:
Hope that helps.
If you want add a NavigationController in appDelegate you can do it like this,in this way,your viewcontroller is load from storyboard
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let vc = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("vc") as! ViewController
let nav = UINavigationController(rootViewController: vc)
self.window?.rootViewController = nav
self.window?.backgroundColor = UIColor.whiteColor()
self.window?.makeKeyAndVisible()
return true
}

Referencing TabbarController created from StoryBoard in AppDelegate?

I have a tabbar app with an initial login screen. The tabbarController is set as the initial view in Storyboard with 1 VC that has a navigationController also embed.
I have a loginVC instantiated and set as rootViewController in my AppDelegate. After the user has successfully sign in from the loginVC, I need to switch over to the tabbarController. Would I try to get a reference to the tabbarcontroller and set it as the new rootviewcontroller? If so, I'm having a hard time figuring out how to do this:/
AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if NSUserDefaults.standardUserDefaults().objectForKey("OAuth") == nil {
self.window = UIWindow(frame:UIScreen.mainScreen().bounds)
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var loginVC = storyboard.instantiateViewControllerWithIdentifier("LOGIN_VC") as LoginVC
self.window?.rootViewController = loginVC
self.window?.makeKeyAndVisible()
}
return true
}
This method gets called after user has successfully signed in
func dismissLoginVC() {
var tabbarController = self.storyboard?.instantiateViewControllerWithIdentifier("TABBAR") as UITabBarController
self.presentViewController(tabbarController, animated: true, completion: nil)
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.window?.rootViewController = tabbarController
}
I know the problem with this is it just created a new tabbarcontroller, rather than referencing the existing tabbarController that was set as the initialView in storyboard. This seems to work but it is missing other items from the navigation bar.
Thanks for pointing me in the right direction!
I think you should change your app structure. Keep the tab bar controller as the initial view controller in the storyboard, and present modally (with no animation) the login controller from the viewDidAppear method of the controller in the first tab -- it will be the first thing the user sees. When you dismiss it, you will be back to that controller in the first tab. With this approach, you don't need any code in the app delegate.

I would like to embed UINavigationController with UITableViewController which is the sub-view of UITabBarViewController by programmatically in Swift

Recently, I want to make an App for self-study and that App looks like Contacts App in iOS. First, I have two UITableViewControllers connecting to UITabBarViewController. Then I want to embed UINavigationController with those 2 tableviews by coding (In this case, I don't want to embed it in Storyboard by design). But I'm stuck with it. Here is my code in AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let tabBar : UITabBarViewController = UITabBarViewController()
let tableView1 : UITableViewController = UITableViewController()
let nav = UINavigationController(rootViewController: tableView1)
let tableView2 : UITableViewController = UITableViewController()
let nav2 = UINavigationController(rootViewController: tableView2)
tabBar.viewControllers = [nav, nav2]
self.window?.rootViewController = tabBar
return true
}
And the result always displays the first tableView1. How can I make it to display two tab options(on the bottom of the view) in UITabBarViewController? If I make it by designing in Storyboard, I'm sure it will work fine. But by coding, I've no idea how to fix it.
Please kindly guide me. Thanks in advance!
There is no UITabBarViewController in UIKit. It is called UITabBarController. Your ViewControllers need to have NavigationItems. If you display them like in your code you will have a Tabbar on bottom but without anything visible on it. In your case the NavigationControllers are the ones where you need to define nav.navigationItem.title = ...
EDIT:
and I realized you are not initializing the window. This is not related to your other problem but you would not see anything with your code. So you have to change it to:
self.window = UIWindow(frame: UIScreen.mainScreen().bounds);
self.window?.rootViewController = tabBar
self.window?.makeKeyAndVisible();

Resources