I have three View Controllers and want to go back from the third to the first on button click. I do the following:
Add the target to my button: doneButton.addTarget(self, action: #selector(ThirdViewController.doneButtonPressed(_:)), for: .touchUpInside)
Create the action in the first controller: #IBAction func unwindFromNewSubscription(segue: UIStoryboardSegue) {
}
Create the unwind segue linking it to the action from #2 in the storyboard and set the "chageFromNewToMain" identifier
Create the action for my button in the third controller: #IBAction func doneButtonPressed(_ sender:UIButton!) {
print("DONE BUTTON PRESSED")
performSegue(withIdentifier: "changeFromNewToMain", sender: self)
}
And it works, BUT when I tap the button in V3 it instantly disappears and I see the animation: V2 slides down, so finally I can see the V1. But I want to animate the V3 to slide down instead of disappearing to see V1 after that. Any ideas how to fix that?
(V1, V2, V3 - View Controller 1, 2, 3)
Try to use presentingViewController?.dismiss(animated: true, completion: nil) inside your #IBAction func doneButtonPressed(_ sender:UIButton!) action instead of calling performSegue(withIdentifier: "changeFromNewToMain", sender: self).
Related
Im a beginner in swift and I am creating a login screen using Material.io in Swift and my UI looks like this .
However i dont see anything on my main.storyboard
I am used to creating a segue manually and then using
performSegue(withIdentifier: <#T##String#>, sender: <#T##Any?#>)
to use the segue but now since i dont see the button i'm unable to use the segue on clicking the 2 buttons Login and Register.
Also, usually from main.storyboard you have an IBOutlet or IBAction block to trigger certain features such as do something on a button click.
How does that work when you use MDCButton for instance. How do you link up the button to an action such as trigger a segue or update a text field.
Thank you.
I have declared my button like this
let nextButton: MDCButton = {
let nextButton = MDCButton()
let containerScheme = MDCContainerScheme()
nextButton.applyTextTheme(withScheme: containerScheme)
nextButton.setTitleColor(.white, for: .normal)
nextButton.translatesAutoresizingMaskIntoConstraints = false
nextButton.setTitle("CREATE NEW ACCOUNT", for: .normal)
nextButton.addTarget(self, action: #selector(didTapNext(sender:)), for: .touchUpInside)
return nextButton
}()
And i am calling it like this
#objc func didTapNext(sender: Any) {
self.performSegue(withIdentifier: "toRegistration", sender: self)
self.dismiss(animated: true, completion: nil)
}
I have a segue linking the 2 view controllers.
I can't see your code and don't have enough rep to comment, but it looks like you are building your view programmatically. To see when the button receives touchUp as you would from an outlet, you need to add a target. Try something like this:
func functionWhereYouCreateTheButton() { (PROBABLY YOUR VIEW DID LOAD)
let loginButton = UIButton()...
...
...
...
loginButton.addTarget(self, action: #selector(self.buttonTapped), for: .touchUpInside)
}
func buttonTapped() {
self.performSegue(withIdentifier: "SEGUEID", sender: self)
}
My storyboard looks like this:
Navigation Controller -> StepOne -> StepTwo -> StepThree
StepOne has a Segue Show to StepTwo etc.
In StepOne I open StepTwo on Button click like this:
#IBAction func next(_ sender: UIButton) {
self.performSegue(withIdentifier: "oneToTwo", sender: self)
}
In StepTwo I open StepThree the same way.
Now In my last StepThree I want to restart at StepOne :
#IBAction func end_click(_ sender: UIButton) {
self.navigationController?.popToRootViewController(animated: false)
}
This works fine.
The problem is that all the UI elements are still filled out from the first run. Of course I could clear all values before I navigate in each controller but this doesn't seem to be good practice.
Is there a way to tell NavigationController to use new instances of its ViewController s ?
I guess you can simply dismiss the root view controller of navigation controller and present it again.
You need
// this inside end_click
let vc = self.storyboard!.instantiateViewController(withIdentifier:"StepOneId")
self.navigationController!.setViewControllers([vc], animated: true)
Sorry if the title is confusing. I have a create post workflow that is on a tab in my tabBar. At the end, there is a "create" button to publish the post. Here is the code attached to pressing that button:
#objc func postButtonPressed() {
let tokens = self.tagsView.tokens()
let tokensArr = tokens!.map({
(token: KSToken) -> String in
return token.title
})
if MyVariables.isScreenshot == true {
PostService.createImagePost(image: self.screenshotOut!, timeStamp: self.postDate!, tags: tokensArr, notes: addNotesTextView.text ?? "")
} else {
PostService.createVideoPost(video: self.videoURL!, timeStamp: self.postDate!, thumbnailImage: self.thumbnailImage!, tags: tokensArr, notes: addNotesTextView.text ?? "")
}
self.tabBarController?.selectedIndex = 0
self.tabBarController?.tabBar.isHidden = false
//performSegue(withIdentifier: "ShowHomeViewController", sender: nil)
}
This works in that the tabBarController switches back to my other Tab. But what I want is for it also to segue back to the cameraView Controller - the first step of the create post workflow so that when the user tabs back to this workflow, they are starting at the beginning and don't come back to the createPost ViewController (the last step) which is what's happening now.
How do I perform this segue "behind the scenes" so that this can happen?
I achieved this by performing an "unwind" segue with in the createPost button...
#objc func postButtonPressed() {
//post code//
...
performSegue(withIdentifier: "unwindToCamera", sender: nil)
}
I added that unwind segue in the interface builder. Then in the CameraViewController I have:
#IBAction func unwindToCamera(sender: UIStoryboardSegue) {
self.tabBarController?.selectedIndex = 0
self.tabBarController?.tabBar.isHidden = false
}
which switches the selectedIndex back to the home screen. However when you tab back over to the camera tab, we are back on the camera view controller because of the unwind segue done prior. This is the desired behavior. The one drawback is that I cannot do an unwind to camera segue without changing the selected tabBar index but my app currently has no reason for me to do that.
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)
}
Currently I have the following storyboard:
UITableViewController -> Segue -> UINavigationController -> Relationship -> UITableViewController
In the last UITableViewController I added a back button with the code below:
navigationItem.setLeftBarButtonItem(UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "unwind"), animated: true)
let attributes = [NSFontAttributeName: UIFont.fontAwesomeOfSize(30), NSForegroundColorAttributeName: Constants.InterfaceColors.firstHighlightColor] as Dictionary!
let unwindNavigationItem = navigationItem.leftBarButtonItem! as UIBarButtonItem
unwindNavigationItem.setTitleTextAttributes(attributes, forState: .Normal)
unwindNavigationItem.title = String.fontAwesomeIconWithName(FontAwesome.AngleLeft)
As far as I read I have to connect the File's owner to the exit in the storyboard. I found out, that this is only possible if you have an action in your controller code like the one below.
#IBAction func unwindToWeekOverview(segue: UIStoryboardSegue) {
NSLog("unwind to week overview")
dismissViewControllerAnimated(true, completion: nil)
}
Since I don't now how to directly connect the action of a button to my unwind action I added the unwind function.
func unwind() {
performSegueWithIdentifier("UnwindToWeekOverview", sender: self)
}
When I now click the back button, the unwind function is called, but not the segue.
What am I missing?
Have a look at this link. It is by MIKE WOELMER and he explains it very clearly.
https://spin.atomicobject.com/2014/10/25/ios-unwind-segues/
So first of all, you need to create an IBAction in a destination view controller, something like this:
#IBAction func goBack(segue: UIStoryboardSegue) {
print("go back")
Then you just need to connect (control drag) from your button to Exit outlet. In the pop up you will see the function added previously, just select it and it should work.