Currently making an app in swift where all elements are added programatically. how can i add segue programmatically for the action of a given button to switch from one view to the next?
Instead of creating segues programmatically, you can use this inside button action to navigate to another view controller.
let viewController = MyViewController()
self.navigationController?.pushViewController(viewController, animated: true)
You can push to your next viewcontroller without using segue as well like.
#IBAction func btnClickNextVC(_ sender: Any) {
let objSecondVc = self.storyboard?.instantiateViewController(withIdentifier: "ViewController2") as? ViewController2
self.navigationController?.pushViewController(objSecondVc!, animated: true)
//or you can use
present(objSecondVc, animated: true, completion: nil)
}
Note: Don't forget to take navigationcontroller in storyboard.
and give storyboard identifier of your viewcontroller same as you pass here in the code withidentifier.
Related
This question already has answers here:
Segue to another storyboard?
(6 answers)
Closed 3 years ago.
Here is my code so far
joinButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
}
#objc func buttonAction(_sender: UIButton) {
print("I want to go to a storyboard here")
}
I have everything coded (never used storyboard), but now I want to actually manually play with the UI now. How can I manually play with the storyboard? Or even render out to a different viewcontroller? Thanks!
You can do it programatically this way:
Swift 3+
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ViewControllerID") as UIViewController
present(vc, animated: true, completion: nil)
You need to assign a Storyboard ID to the view controllers you are going to use programatically:
Select storyboard
Go to Identity Inspector (⌥⌘3)
Assign Storyboard ID
If you want to add manual segue in Storyboard (Note: you can have multiple manual segues):
Select storyboard
Select the source view controller
Go to Connections Inspector (⌥⌘6)
In the Triggered Segues, drag the dot beside manual to the target view controller and select the desired method
In Document Outline, select "Show segue..." and go to Attributes Inspector (⌥⌘4) and assign an Identifier
In your button function, you can simply use the segue by:
self.performSegue(withIdentifier: "<IdentifierForSegue>", sender: self)
Or if you do not wish to use a manual segue:
// If view controllers are in the same Storyboard
let storyboard = self.storyboard!
// If view controllers are in different Storyboards
// let storyboard = UIStoryboard.init(name: "<NameOfYourStoryboard>", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "<IdentifierForTargetViewController>")
// If you don't have a navigation controller
self.present(viewController, animated: true, completion: nil)
// If you have a navigation controller
// self.navigationController?.pushViewController(viewController, animated: true)
I have 3 ViewController : LoginViewController, CheckinViewController, & ProfileViewController
The flow is :
LoginVC --> CheckinVC --> ProfileVC
What i need is:
I want to dismiss "ProfileVC" & "CheckinVC" when click logout button in "ProfileVC" then go back to the "LoginVC"
LoginVC.swift
let checkinViewController = self.storyboard?.instantiateViewController(withIdentifier: "CheckinViewController") as! CheckinViewController
self.navigationController?.pushViewController(checkinViewController, animated: true)
JustHUD.shared.hide()
self.dismiss(animated: false, completion: nil)
CheckinVC.swift
if let profileView = self.storyboard?.instantiateViewController(withIdentifier: "ProfileViewController") {
profileView.providesPresentationContextTransitionStyle = true
profileView.definesPresentationContext = true
profileView.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext;
// profileView.view.backgroundColor = UIColor.init(white: 0.4, alpha: 0.8)
profileView.view.backgroundColor = UIColor.clear
profileView.view.isOpaque = false
self.present(profileView, animated: true, completion: nil)
Here is i'm trying to do
ProfileVC.swift
#IBAction func clickLogout(_ sender: Any) {
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
UserDefaults.standard.synchronize()
self.dismiss(animated: false, completion: {
print("ProfileView : dismiss completed")
let loginViewController = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.navigationController?.pushViewController(loginViewController, animated: true)
self.dismiss(animated: false, completion: {
print("SUCCESS")
})
})
}
Well you need to do an Unwind Segue so you can go back in your LoginVC.
Follow these simple four steps to create Unwind segues:
In the view controller you are trying to go back to, LoginVC in your example, write this code:
#IBAction func unwindToVC1(segue:UIStoryboardSegue) { }
( Remember: It’s important to insert this method in the view
controller you are trying to go back TO! )
In the Storyboard, go to the screen you’re trying to unwind from ( ProfileVC in our case ), and control + drag the viewController icon to the Exit icon located on top.
3. Go to the document outline of the selected viewController in the Storyboard, select the unwind segue as shown below.
Now, go to the Attributes Inspector in the Utilities Pane and name the identifier of the unwind segue.
Finally, write this code where you want the unwind segue action to be triggered, ProfileVC in our case.
#IBAction func clickLogout(_ sender: Any) {
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
UserDefaults.standard.synchronize()
performSegue(withIdentifier: "unwindSegueToVC1", sender: self)
}
For more information check Create Unwind Segues
While Enea Dume's solution is correct if you want to use storyboards, here is the explanation of the problem, and the solution if you want to do it in code like you have been so far.
The Issue
If we focus on the self.dismiss calls in the logoutFunction in ProfileVC, this is what happens.
The first time you call self.dismiss, ProfileVC will dismiss itself and be removed from the view stack.
In the completion delegate, you are pushing a new LoginVC to a navigation controller. However, the CheckIN VC is presented over the navigation controller so you can't see anything happen.
The second call to self.dismiss does nothing as ProfileVC is not presenting any other view controllers and it is not in the stack any longer.
The Solution
You need to keep a reference to LoginVC that presented the CheckInVC. If you call "reference to LoginVC".dismiss, it will dismiss the view controllers above it in the stack and take you back to the login view controller.
In the class CheckinVC.swift, in the function viewDidAppear, check if the user is still active or not based on the session that you are maintaining and the pop to login view controller accordingly. If user status is logged out, then it will go to login view controller. Else it will work as usual.
Problem is that you are trying to dismiss twice ProfileVC but what you actually need is to dismiss it and then pop CheckinVC.
Also after dismissing a view controller it no longer has a reference to the NavigationController so you need a reference to it in a temporal variable.
Change ProfileVC like this:
#IBAction func clickLogout(_ sender: Any) {
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
UserDefaults.standard.synchronize()
let navigationController = self.navigationController
let loginViewController = storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.dismiss(animated: false, completion: {
print("ProfileView : dismiss completed")
navigationController?.pushViewController(loginViewController, animated: true)
navigationController?.popViewController(animated: false)
})
}
I want to segue to a new ViewController programatically but when I do my tabBar disappears.
if user == usernameStored && pass == passwordStored{
print("Good")
let vc = self.storyboard?.instantiateViewController(withIdentifier: "home")
self.present(vc!, animated: true, completion: nil)
}
From your code, this is not segue by programmatically. You actually present a viewController on top of whatever you have. Therefore the tabBarController is cover.
To use segue in code, it should be something like this. - homeSegueID is the identifier you give when you created the segue in storyboard.
performSegue(withIdentifier: "homeSegueID", sender: nil)
If you just want to do it programatically without segue, you could do this instead. (This assume your current ViewController is in a UINavigationController stack.
navigationController?.pushViewController(vc, animated: true)
Is the navigation controller wrapping your view controllers a tab bar controller, or did you just add the tab bar to your view controller? This is what you should be doing:
I am trying to create segues between my UIViewControllers but am having some difficulties with creating a segue from a UITableViewCell and a UIButton.
When I create a show detail segue through storyboard from a UITableViewCell to a UIViewController it works perfectly and I get the back button showing up. But when I try to create a show detail segue from a UIButton to a UIViewController it doesn't register the navigation stack and presents the screen modally without the back button.
How can I make a successful show detail segue from a UIButton to a viewcontroller? I am new to iOS and am having trouble determining why the UIButton segue doesn't behave the same as the UITableViewCell segue.
Thanks in advance for any help!
Dont connect a segue manually do it through button action.
This is assuming the viewController that has this button is the root view controller of the navigation controller
#IBAction func myButtonTapped(_ sender: Any) {
let vc = self.storyboard!.instantiateViewController(withIdentifier: "YOUR STORYBOARD IDENTIFIER GOE HERE")
self.show(vc, sender: self)
}
If you want to go to a tab of a tab bar controller you have to specify its index. I think you can set it in storyboard but i just go with 0 is on the left then they go up sequentially. so in the example below i want to go to the second tab of the tab bar controller with a modal transition. I assume you can use show here like example above I've just never done it.
let tbc = self.storyboard!.instantiateViewController(withIdentifier: "MyTabController") as! UITabBarController
tbc.selectedIndex = 1 // this is 2nd tab index.. start at 0
tbc.modalPresentationStyle = .overCurrentContext
tbc.modalTransitionStyle = .coverVertical
self.present(tbc, animated: true, completion: { finished in
// you can also do some completion stuff in here if you require it.
// self.view.removeFromSuperview()
// self.navigationController?.navigationBar.removeFromSuperview()
})
let vc = self.storyboard!.instantiateViewController(withIdentifier: "StoryBoardID")
self.navigationController?.pushViewController(vc, animated: true)
I have two view controllers and a button in my storyboard. I don't understand why this is not pushing the view to the second view controller. I have the Storyboard ID and Class of FirstViewController, so shouldn't it work? I keep getting this error Unknown class FirstViewController in Interface Builder file. What am I doing wrong?
#IBAction func button(sender: AnyObject) {
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("FirstViewController")
self.navigationController?.pushViewController(viewController!, animated: true)
}
Just to have an answer for others -->
Two ways to solve it ->
1.Add a navigationController in the storyboard, as you cannot do pushViewController on a viewController outside navigationController's stack.
2.You can push it as a modal view controller, using self.presentViewController(viewController, animated: true, completion: nil)
This will give a modal effect, and not the normal push effect.