I am trying to fix up an edit segue (show in IB) where I can click the 'Edit report details' button on the toolbar and it will Show Segue towards the 'Configure Report' View controller.
However, if I click cancel, it goes all the way back to my login screen, because presentingViewController is a UINavigationController, even though it shouldn't be.
Here's the story board. http://i.imgur.com/DK4HhpO.png
Any ideas?
// MARK: Navigation
#IBAction func cancel(sender: UIBarButtonItem) {
// Depending on style of presentation (modal or push presentation), this view controller needs to be dismissed in two different ways.
let isPresentingInAddItemMode = presentingViewController is UINavigationController
if isPresentingInAddItemMode {
dismissViewControllerAnimated(true, completion: nil)
}
else {
// In this mode (push presentation), we need to pop the view controller to get rid of it, rather than dismissing
navigationController!.popViewControllerAnimated(true)
}
}
This is all I do in my code and it works.
#IBAction func cancel(sender: AnyObject) {
self.navigationController?.popViewControllerAnimated(true)
}
How ever you may need to check for which segue identifier sent you first.
#IBAction func cancel(sender: AnyObject) {
if (segue.identifier == "Edit") {
self.navigationController?.popViewControllerAnimated(true)
} else if (segue.identifier == "Add") {
self.navigationController?.popViewControllerAnimated(true)
}
This way it knows which one to follow. It also may depend on how you are segue to the view in the first place.
Related
I'm working on an app where I have an error page displayed incase there is a network problem. The app has several storyboards, and this can happen anywhere.
func displayErrorPage(errorCode: ErrorCode) -> Void {
if !isDisplayingError {
DispatchQueue.main.async {
self.isDisplayingError = true
let storyboard = UIStoryboard(name: "alert", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "AlertScreen") as! AlertVC
controller.errorCode = errorCode
UIApplication.shared.topViewController?.present(controller, animated: true, completion: nil)
}
}
}
I would like to use unwind to dismiss it, to clear out any views and get back to the home page. I have used this in the alert view to close, but sometimes doesn't work.
#IBAction func closeBtn(_ sender: Any) {
flowError = true
NetworkManager.shared().isDisplayingError = false
performSegue(withIdentifier: "unwindToSH", sender: self)
}
Anyone with some pointers?
Create the unwind segue IBAction in the view controller you want to unwind to.
Perhaps in your case it is HomeViewController. Add this code inside your HomeViewController
#IBAction func unwindToHomeVC(segue: UIStoryboardSegue) {}
Wire up the unwind segue - Control drag from AlertVC’s ViewController icon to exit icon in the storyboard choose the unwind segue action (unwindToHomeVC) that was created in step 1 from the list of IBActions.
Specify a segue Identifier - specify its identifier in the Attributes Inspector of the Utilities Pane. Ex: “unwindToHomeVC”
Trigger unwind segue programmatically - trigger that in the appropriate place. In your case close button action
self.performSegue(withIdentifier: "unwindToMenu", sender: self)
It will work even if you work with multiple storyboard as well, if your setup is right. I hope that this one would help you.
Thanks
I have a TabBarController in my Main.storyboard file.
In my Upload.storyboard I am presenting a ViewController from the Main.storyboard file, however, it doesn't contain the tab bar.
The viewProfile button should go to a tab called Sharks and within that present a view controller based on data gathered in the Upload.storyboard (modal view).
Can I add the tab bar programmatically or am I not properly presenting the correct VC?
// MARK: - Actions
#IBAction func viewProfileButtonPressed(_ sender: UIButton) {
let stb = UIStoryboard(name: "Main", bundle: nil)
let sharkProfile = stb.instantiateViewController(withIdentifier: "sharkProfile") as! SharkProfileTableViewController
self.present(sharkProfile, animated: true) {
// add tab bar here?
}
}
What you need to do is present the tab bar view controller, not the view controller that is embedded in it
One method is to create a Delegate Protocol to allow a tap on View Profile button to "call back" to the View Controller that presented it. When that callback is received, the VC sets the "current" tab.
It will look something like this:
// define "call back" delegate protocol
protocol EncounterUploadedDelegate : class {
func didTapSharkProfileButton()
}
The Encounter view controller will need to conform to that protocol:
class EncounterViewController: UIViewController, EncounterUploadedDelegate {
// the normal stuff for this VC and all the other code for it
// ...
// conform to the protocol
func didTapSharkProfileButton() -> Void {
// when we get this call-back, switch to the Shark Profile tab
// tabs are zero-based, so assuming "SharkProfile" is
// is the 4th tab...
self.tabBarController?.selectedIndex = 3
}
// assuming a "Show Modal" segue named "ShowEncounterUploadSegue" is used
// to present the Modal View
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEncounterUploadSegue" {
let vc = segue.destination as! TabModalVC
vc.encounterDelegate = self
}
}
}
The view controller to be presented as modal:
class TabModalVC: UIViewController {
weak var encounterDelegate: EncounterUploadedDelegate?
#IBAction func profileButtonTapped(_ sender: Any) {
// dismiss self (the modal view)
self.dismiss(animated: true, completion: nil)
// this will call back to the delegate, if one has been assigned
encounterDelegate?.didTapSharkProfileButton()
}
}
Hope that all makes sense :)
i have a project where initial viewcontroller does not have a navigation controller a loguin windows after that i have a navigatino controller to the main view. so when I tap on close session i make a segue to loguin windows but that does not destroy any windows opened in previous, so I google for a solution an i show a unwindsegue to main viewviewcontroller but always the initial view controller is behind a navigation controller so my real question is is a valid approach to make
#IBAction func unwindToVC1(segue:UIStoryboardSegue) {
self.performSegue(withIdentifier: "goLogin", sender: nil)
}
You need change sender value nil to self value:
#IBAction func unwindToVC1(segue:UIStoryboardSegue) {
self.performSegue(withIdentifier: "goLogin", sender: self)
}
Basically, I have a button in a slide-out menu (which is its own view controller that covers part of the Origin screen, let's call it Menu) that, when pressed, performs a modal segue to another controller, let's say Destination.
Is there any way that upon pressing the button in Menu (to go to Destination), that I can dismiss Menu back to Origin, and THEN segue to Destination?
It sounds silly but it's something that I think I've seen apps do before. In my case, the reason for wanting to do this is that once I press "Done" on Destination, it dismisses that controller back to Menu, when I want it to just dismiss back to Origin. I can't just perform a segue back to Origin from Destination.
Code:
This is how I open the Menu from Origin:
let interactor = Interactor()
#IBAction func openMenu(_ sender: AnyObject) {
performSegue(withIdentifier: "openMenu", sender: nil)
}
#IBAction func edgePanGesture(sender: UIScreenEdgePanGestureRecognizer) {
let translation = sender.translation(in: view)
let progress = MenuHelper.calculateProgress(translationInView: translation, viewBounds: view.bounds, direction: .Right)
MenuHelper.mapGestureStateToInteractor(
gestureState: sender.state,
progress: progress,
interactor: interactor){
self.performSegue(withIdentifier: "openMenu", sender: nil)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationViewController = segue.destination as? MenuViewController {
destinationViewController.transitioningDelegate = self
destinationViewController.interactor = interactor
destinationViewController.currentRoomID = self.currentRoomID
}
}
This is my prepareForSegue from Menu to Destination currently, nothing fancy:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
let inviteVC = segue.destination as! InviteVipViewController
inviteVC.currentRoomID = self.currentRoomID
}
And finally to dismiss Destination is just a simple
#IBAction func cancelButtonPressed(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
I saw this question which is basically what I'm trying to do but there was no answer unfortunately: Performing segue after dismissing modal swift
Sorry if this sounds confusing, but if anyone knows what I'm talking about and can let me know how I can set up the segues/prepareForSegues to make it work, any input would be appreciated!
Based on a modification to this answer, the following should work:
In your storyboard, remove the segue that is triggered by tapping your menu button and goes to Destination.
Create a new segue that goes from the Origin view controller to Destination view controller. This segue is going to be manually performed.
When your Destination option is selected in Menu, have Menu dismiss itself and then perform the Destination segue on Origin, like this:
// This code goes in Menu, and you should call it when
// the menu button is tapped.
//
// presentingViewController is Origin
weak var pvc = self.presentingViewController
self.dismiss(animated: true) {
// Menu has been dismissed, but before it is destroyed
// it calls performSegue on Origin
pvc?.performSegue(withIdentifier: "openDestination", sender: nil)
}
When Destination is dismissed, you should see Origin, without seeing Menu at all.
I tested this in a sample app where "Menu" was not a slide out, but a full modal view controller, and it worked for me.
EDIT: While troubleshooting with #KingTim, he found that we needed to wire the segue from the UINavigationController, not Origin, to the Destination. This is because Origin is inside a navigation controller. After that discovery, it worked.
If your presenting view is embedded in a navigation controller then you can do this:
weak var pvc:UIViewController! = self.presentingViewController?.childViewControllers[0]
dismiss(animated: true)
{
pvc.performSegue(withIdentifier: "SegueID", sender: nil)
}
Simple solution with presentingViewController
if let destinationVC = self.presentingViewController as? YourViewController {
destinationVC.isBooleanPassed = true
destinationVC.selectedString = "here comes your string"
destinationVC.selectedInteger = 12345
}
dismiss(animated: true, completion: nil)
I have a navigation tableview controller Calculator and that goes to AddActiveIngredients which is where I add everything in for the calculator.
I have the segue method backButton in Calculator and in AddActiveIngredients I have click dragged the segue from the controller to exit and selected the segue in the Calculator class.
The segue identifier is also backButton but it's not doing anything.
I've tried this code to try and trigger the segue manually but that's not working. Am I missing something so simple?
override func didMoveToParentViewController(parent: UIViewController?) {
if (!(parent?.isEqual(self.parentViewController) ?? false)) {
print("Back Button Pressed!")
self.performSegueWithIdentifier("backButton", sender: self)
}
}
It sounds like you just want to remove the AddActiveIngredients from the stack. If so, you just need to call a function to dismiss it.
func dismissVC() {
dismissViewControllerAnimated(true, completion: nil)
}
You can put that in a button tap or something else. It'll work with Show and Modal segues. Unwinding may be overkill for what you're doing.
Hope it helps!
To use the Exit icon you need not create a segue at all.
All you have to do is add a method in the ViewController to which you want to unwind to and add a method with the signature:
#IBAction func myUnwindAction(segue: UIStoryboardSegue) {
// do stuff
}
Remember, you have to add this method in the target ViewController
When you Control-Drag from a button to the Exit icon, this method will now show up.
When you now click the button, the current ViewController will be popped and the action method in the target will be called.
Hope this helps.
with Swift 5 you can use Dismiss function
#IBAction func dismissViewController(_ sender: Any) {
//Go back to previous controller
dismiss(animated: true, completion: nil)
}