This question already has answers here:
How to push and present to UIViewController programmatically without segue in iOS Swift 3
(3 answers)
Closed 3 years ago.
My problem is that I can't find the correct code to transition between two scenes in IOS programatically. I have tried a few example codes, but none of them work as expected.
let vc storyboard!.instantiateViewController(withIdentifier: "savedMode") as! SavedModeViewController
let navigationController = UINavigationController(rootViewController: vc)
self.present(navigationController, animated: true, completion: nil)
This code goes to the new scene, but the back button doesn't appear in the left side of the navigation bar, and transition between scenes is wrong; instead of left to right animation, there is bottom to top animation.
let controller = storyboard?.instantiateViewController(withIdentifier: "savedMode") as! SavedModeViewController
present(controller, animated: true, completion: nil)
This is the second code I have tried. The problem is that with this code, the navigation bar doesn't show at all in the second scene.
I have tried another way, but instead of second scene, the screen just turned black.
Calling present will present the new view controller modally over the current view controller.
What you want is to push the new view controller onto the existing UINavigationController with pushViewController .
if let savedVC = storyboard?.instantiateViewController(withIdentifier: "savedMode") as? SavedModeViewController,
let navigationController = self.navigationController {
navigationController.pushViewController(savedVC, animated: true)
} else {
// TODO: Handle unexpected nil occurrences
print("Error loading SavedModeViewController")
}
Related
I'm trying to recreate the effect where the view controller underneath the one I'm presenting onto the user's iPhone is positioned behind the presented view controller so you can see the top of the previous VC.
#objc func showSteps() {
let vc = UIStoryboard(name: Storyboards.Main.rawValue, bundle: nil).instantiateViewController(withIdentifier: HowToSteps.four.stepAsString())
vc.modalPresentationStyle = .pageSheet // I've also tried the other enum options here to no effect
let nc = UINavigationController(rootViewController: vc)
present(nc, animated: true)
}
However the presented view controller just comes up as full screen without the ability to see the view controller underneath behind it.
Any help here would be appreciated. Thanks!
Edit:
The effect I'm going for:
This question already has answers here:
Change initial view controller after first launch of app
(2 answers)
Closed 5 years ago.
The starting point for my app is a simple login screen. If the user wants to make a new account, then they will segue into a navigation controller which manages all the views for creating a new account. The problem is that after they have made the account and signed in, the navigation bar is still there (pressing the back button will bring them to the "enter a password" page). I don't want to simply hide the navigation bar, I want the navigation controller and it's whole stack of views to be gone completely.
First of all after a successfull registration don't wait the user to click back or any thing automatically direct it to the main content VC of the app by changing the root of the AppDelegate's window to the mainVC embeded in a navigation controller , so later you can push other VCs to it like user settings , about VCs and so on
first create a new nav
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier :"mainView") as! mainViewController
let navController = UINavigationController.init(rootViewController: viewController)
and assign it to root
let appDelegate = UIApplication.shared.delegate as? AppDelegate
appDelegate?.window?.rootViewController = navController
You can Remove login screen from navigation controller using below code:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
var tempVCs = self.navigationController?.viewControllers
for tempVC: UIViewController in tempVCs {
// remove login screen from navigation stack
if (tempVC is LoginScreenVC) {
tempVC.removeFromParentViewController()
}
}
}
In my project i want to present Tabbar on button click, now i have already created tabbar and i give identity name as "tabbar" that i show you in below image
so now i am using below code to call Tab bar controller but i am not getting it.
let tabbar: UITabBarController? = (storyboard.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController)
navigationController?.pushViewController(tabbar, animated: true)
can you guys suggest me what i need to do and which code is useful to me to present Tabbar controller.
For more specification : i added below image in which there is blue button in one viewController i want to present tab bar controller on click of that blue button
Thank you.
Try this and see:
Using Storyboard Segue: Connect your segue as present modally with your action button.
Programatically: Use self of view controller (UIViewController) and present it modally, like this.
if let tabbar = (storyboard.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController) {
self.present(tabbar, animated: true, completion: nil)
}
Here is result:
Use this, you dont have the Navigation controller over there, thats why it won't push that way, instead, you need to use following code:
self.present(tabbar, animated: true, completion: nil)
You should be aware that Apple's HIG (Human Interface Guidelines) say that if you have a tabbed application that should be the root-level navigation for the entire app. you're not supposed to do what you are trying to do from a human interface perspective.
That said, it should be technically possible.
My guess is that you don't have a navigation controller.
Use the debugger to check the value of self.navigationController, or add a print statement:
let tabbar: UITabBarController? = (storyboard.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController)
print("navigationController = \(navigationController)")
print("tabbar = \(tabbar)")
navigationController?.pushViewController(tabbar, animated: true)
If either navigationController or tabbar displays as nil, that's your problem.
Select the viewController from which the button click triggered and Select Editor form xcode menu->Embed In->NavigationController.
then write this in button action
let tabbar: UITabBarController? = (self.storyboard?.instantiateViewController(withIdentifier: "tabbar") as? UITabBarController)
self.navigationController?.pushViewController(tabbar!, animated: true)
According to your images I think that your tabBarController has no back button. Means user cannot go back.
If that is the case you can do this.
let tabBar = self.storyboard?.instantiateViewController(withIdentifier: "tabBar")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBar
I'm currently writing an app where we are launching a walkthrough the first time the user opens the app. At the end of it, we require the user to fill in a few details, and to do so I would like him to press a button to get redirected to the settings page.
The thing is, this page is one level down the navigation controller (from the landing page). As it stands, I can correctly instantiate the landing page, but the redirection to the settings page never happens.
let mainView = self.storyboard?.instantiateViewControllerWithIdentifier("NavCtrl")
self.presentViewController(mainView!, animated: false, completion: nil)
// the above works correctly and sends us to the landing screen
// (rootView of the navigation controller)
// the following lines never have any effect though
let settingsView = self.storyboard?.instantiateViewControllerWithIdentifier("Settings View")
self.navigationController?.pushViewController(settingsView!, animated: false)
I think it's because I'm trying to call .pushViewController before the storyboard had time to instiate either the first or second view.
So I have a few questions:
Is there a way to, indeed, instantiate a view and then navigate to another one right after it has been instantiated ? (this in order to keep the navigation stack and maintain accurate nav bar behaviour)
If there isn't, would it be possible to programmatically populate the navigation stack so that I would only need to instantiate the settings view ? This in order to still have the back button in the nav bar that would send to the landing screen ?
Thanks in advance guys
Ok thanks to #Leonardo for showing me the correct direction !
I solved the issue by doing the following in appDelegate:
/*
* Override window root view and set it to a newly initialized one
* view: StoryboardID of view to display
* navigateTo: if true, set the root view to NavCtrl and then navigate to the desired view
*/
func setWindowViewTo(view: String, navigateTo: Bool) {
//initalize storyboard & window programmatically
window = UIWindow.init(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
//if true, navigate from landing page to specified view through navigationController
if(navigateTo) {
//instantiate the navigation controller
let navCtrl = storyboard.instantiateViewControllerWithIdentifier("NavCtrl") as! UINavigationController
//instantiate the landing page & the page we wish to navigate to
let landingView = storyboard.instantiateViewControllerWithIdentifier("Main View")
let vc = storyboard.instantiateViewControllerWithIdentifier(view)
//manually set the navigation stack to landing view + view to navigate to
navCtrl.setViewControllers([landingView, vc], animated: false)
//replace the rootViewController to the navigation controller
window!.rootViewController = navCtrl
//make it work
window!.makeKeyAndVisible()
} else {
window!.rootViewController = storyboard.instantiateViewControllerWithIdentifier(view)
window!.makeKeyAndVisible()
}
}
The important step was to indeed force downcast as! UINavigationController when instantiating the NavigationController with the storyboard.instantiateViewControllerWithIdentifier() method.
Then it's just a case to correctly instantiate the views of the navigation stack you want, and finally calling navCtrl.setViewControllers([view1, view2], animate: false).
Thanks all for your help !
You can use the - setViewControllers:animated: method to set the navigation stack of a UINavigationController
Here's the reference
But I don't think that's your problem, if I undestood your code correctly, it should be
//This is the navigation controller
if let mainView = self.storyboard?.instantiateViewControllerWithIdentifier("NavCtrl"){
//Nav being modally presented
self.presentViewController(mainView, animated: false, completion: nil)
// Instantiate the settings view
if let settingsView = self.storyboard?.instantiateViewControllerWithIdentifier("Settings View"){
//Push it to the navigation controller presented
mainView.pushViewController(settingsView, animated: false)
}
else{
//Can't Instantiate, deal with error
}
}
else{
//Can't Instantiate, deal with error
}
This is my storyboard:
Short Description:
My App starts with the LaunchController
a modal segue shows the Reveal View Controller
this bring the Menu Controller and my Main Navigation Controller (ID
"NavController"; green Navbar) together. this will create a slide
menu. (Basic Code:
appcoda.com/ios-programming-sidebar-navigation-menu/)
my Main Navigation Controller shows a TableViewController.
this one have a menu button (3 Lines) which make the slide menu
visible
the plus icon willo push the last view Controller (ID: "VC1").
My Problem:
I would like to set quick actions for my app.
This code help works for that:
#available(iOS 9.0, *)
func handleShortcut( shortcutItem:UIApplicationShortcutItem ) -> Bool {
var succeeded = false
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("NavController")
self.window?.rootViewController = initialViewController
let navVC = self.window?.rootViewController as! UINavigationController
switch shortcutItem.type {
default:
navVC.pushViewController(storyboard.instantiateViewControllerWithIdentifier("VC1"), animated: false)
succeeded = true
break
}
return succeeded
}
This Code set the NavController as initial Controller und push the to VC1.
This works fine.
With the X icon in VC 1, i use the unwind function back to TableView.
The Problem: if i use the undwind function and fall back to tableview i can't open the slide menu. A Touch on the menu icon give no reaction.
The Problem can be, that i start the app with the quick action behind the Reveal View Controller.
How can I solve this problem?
Did you try to make the reveal view controller the entry point of your app and deleting the launch controller, because if you just want to go back to the main view you could just do this :
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateInitialViewController() as UIViewController!
self.presentViewController(controller, animated: false, completion: nil)
If you cannot could you explain the purpose of the launch controller?