How to go back from one viewcontroller to other viewcontroller - ios

I have a simple one for you guys. I have created a back button on a UITableviewController, and want to set that back button to my other UIViewController(NewTableViewController).
here i implemement back button
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(NewTableViewController.back(sender:)))
self.navigationItem.leftBarButtonItem = newBackButton
and action is
func back(sender: UIBarButtonItem) {
// perform your custom action
//....
// go back to the previuos view controller
_ = navigationController?.navigationController?.self.dismiss(animated: true)
}
but i am unable to go back
Thanks for the help you guys. Please tell me what I am missing.

Try this for swift 3
If you use model view controller
func back(sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: {});
}
OR
If you use push
func back(sender: UIBarButtonItem) {
if let navController = self.navigationController {
navController.popViewController(animated: true)
}
}

Related

UIBARBUTTON back action

let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: Selector(("HomeTabController")))
self.navigationItem.leftBarButtonItem = backButton
The above code is the creation of button in navigationController but I can create a button cannot write a specific view controller to open.
I have tried with popViewController and popToRootViewController action, need a specific code for opening a particular viewController in swift, with the help of the particular viewController storyboard id and viewcontrollername.
You need to add func name in #selctor() (Swift 4 version)
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(goToViewController(_:)))
self.navigationItem.leftBarButtonItem = backButton
You need to create a func.
#objc func goToViewController(_ sender: UIBarButtonItem) {
//write code here to open a view controller
let storyboard = "Main"
let viewControllerIdentifier = "HomeVC"
let viewController = UIStoryboard(name: storyboard, bundle: nil).instantiateViewController(withIdentifier: viewControllerIdentifier) as! HomeVC
//push/present "viewController"
}
in this code just replace ChatVC name to your viewcontroller name
#objc func goToViewController(_ sender: UIBarButtonItem) {
for controller in self.navigationController!.viewControllers as Array {
if controller.isKind(of: ChatVC.self) {
self.navigationController!.popToViewController(controller, animated: true)
break
} else {
self.navigationController?.popViewController(animated: true)
}
}
}

UIBarbuttonItem dismiss UIVIewcontroller

I added an extension to UIViewController to add a close button
extension UIViewController {
func addCloseButton() {
let button = UIBarButtonItem(image: #imageLiteral(resourceName: "bar_close"),
landscapeImagePhone: nil,
style: .done,
target: self,
action: #selector(UIViewController.dismiss(animated:completion:)))
navigationItem.leftBarButtonItem = button
}
}
When i tap the barbutton i get a crash directly to AppDelegate.
Any hints? Seems related to the selector.
You can't use dismiss(animated:completion:) as selector here because it takes two arguments bool and closure and bar button action pass args as UIBarButtonItem which cause app crash.
so change your code like this.
extension UIViewController {
func addCloseButton() {
let button = UIBarButtonItem(image: #imageLiteral(resourceName: "rightgreen"),
landscapeImagePhone: nil,
style: .done,
target: self,
action: #selector(onClose))
navigationItem.leftBarButtonItem = button
}
#objc func onClose(){
self.dismiss(animated: true, completion: nil)
}
}
However this question has accepted answer which load extra one method addCloseButton in each and every viewcontroller still posting a answer will going to help someone
NOTE : This example for adding barbutton item automatically and also handle action for pop view controller.
As Protocol extension doesn't provide a to implement selector methods so to get the rid of it I have created this solution.
First thing you need is BaseVC which is subclass of UIViewController and all of your view controller going to be inherited by BaseVC like your class LoginVC:BaseVC ...
now declare protocol
protocol PopableClass {
func popSelf (animated:Bool)
}
extension PopableClass where Self : UIViewController {
func popSelf (animated:Bool) {
self.navigationController?.popViewController(animated: animated)
}
}
In your Base VC add two methods and call setupNavigationBar from viewDidLoad
func setupNavigationBar () {
if self is PopableClass {
let barbuttonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "back"), landscapeImagePhone: #imageLiteral(resourceName: "back"), style: .plain, target: self, action: #selector(popViewController))
self.navigationItem.leftBarButtonItem = barbuttonItem
}
}
//--------------------------------------------------------------------------------
#objc func popViewController () {
if self is PopableClass {
(self as! PopableClass).popSelf(animated: true)
}
}
You did it !!
Now in whatever class you need back button to pop view controller just use like this
class PushedClass: BaseVC,PopableClass
Hope it is helpful

Swift: Edit Mode, link editButtonItem() to IBAction

I understand how to set my UITableView into edit mode, and how to dynamically create an edit button:
override func viewDidLoad() {
tableView.allowsMultipleSelectionDuringEditing = true
tableView.setEditing(false, animated: false)
navigationItem.leftBarButtonItem = editButtonItem()
}
But when I tap the edit button, I would like a new button to appear on the navigation bar (i.e. a 'plus'/'add' button). To do this I think I need to create an IBAction, but I don't know how to link the editButtonItem() to an action. Any ideas?
Ok, big thanks to Ahmed and vadian for their comments, but what I got working was this:
override func setEditing(editing: Bool, animated: Bool) {
// Toggles the edit button state
super.setEditing(editing, animated: animated)
// Toggles the actual editing actions appearing on a table view
tableView.setEditing(editing, animated: true)
if (self.editing) {
navigationItem.rightBarButtonItem =
UIBarButtonItem(barButtonSystemItem: .Add, target: self,
action: #selector(clickMe))
} else {
// we're not in edit mode
let newButton = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.Plain, target: navigationController, action: nil)
navigationItem.rightBarButtonItem = newButton
}
}
func clickMe()
{
print("Button Clicked")
}
As the edit button is pressed (and flips from Edit -> Done and back again) the code in the IF/ELSE statements will execute.
You can replace the default action of editButtonItem() by assigning a new function defined in your view controller to its action property.
editButtonItem().action = #selector(yourCustomAction(_:))
func yourCustomAction(sender: UIBarButtonItem) {}

How do I create a cancel button?

I am having troubles getting my cancel button to work. I have this action connected to my cancel button and I plan to dismiss the view controller like so:
#IBAction func cancel(sender: UIBarButtonItem) {
dismissViewControllerAnimated(true, completion: nil)
}
I was wondering what obvious bit I am missing. (This is a bar button item for a table view).
var b = UIBarButtonItem(title: "Cancel", style: .Plain, target: self, action: "Cancel clicked")
If you wanted the method to take the sender as a parameter, you would put a colon at the end:
var b = UIBarButtonItem(title: "Cancel", style: .Plain, target: self, action: "CancelClicked:")
func CancelClicked(sender: UIBarButtonItem) {
}
After you add the NavigationBar (and Navigation Item) to the Storyboard using IB, the reference to navigationItem var will be automatically mapped to your ViewController file. Add the code below to attach a cancel button to the navigationItem to dismiss the modal View Controller:
#IBOutlet weak var navigationBar: UINavigationBar!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelClicked(sender:)))
}
func cancelClicked(sender: UIBarButtonItem) {
print("Cancel clicked!")
self.dismiss(animated: true, completion: nil)
}
Try this:
#IBAction func close(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
Your code works fine with one little fix. Dismiss is called on the presenting controller. self.dismissViewController would dismiss child view controller presented by the current vc. but if you wanna dismiss the existing vc you should call dismiss on the parent
#IBAction func cancel(sender: UIBarButtonItem) {
presentingViewController.dismissViewControllerAnimated(true, completion: nil)
}

Segue through navigationcontroller

So I have a button in [2] and it pushes to [3] through the Navigation Controller so I can go back to [2] with the "Back" button in the toolbar. This all works fine.
In [4] I have a button too and I want it to go to [3]. But it should also go through the navigation controller so that when I press "Back" I can return to [2] again.
So actually I want the button on [4] to go like [ 1 ][ 2 ][ 3 ] so that I can return to [2] from [3]
#IBAction func showKaart(sender: AnyObject) {
performSegueWithIdentifier("menuToKaart", sender: sender)
}
If I understand your question, I believe try it.
Mind your root view controller is vc[2], ok?
You push from vc[2] > vc[3], next press back and return to vc[2], that's ok!
You push from vc[4] > vc[3], next press back and return to vc[4], but you need back to vc[2]?
For this logic you can create your custom behavior to vc[3]
For your vc[3] I do this to control behavior.
class ViewController3:UIViewController{
var backToRoot:Bool = false;
override func viewDidLoad() {
super.viewDidLoad();
self.hideAndAddNewBackButton();
}
private func hideAndAddNewBackButton(){
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton;
}
func back(sender: UIBarButtonItem) {
if backToRoot{
self.navigationController?.popToRootViewControllerAnimated(true);
}else{
self.navigationController?.popViewControllerAnimated(true)
}
}
func needBackToRoot(){
backToRoot = true;
}
}
Now in vc[4] I think you can modify the back button behavior of your vc[3]
I mind two way to do with your vc[4]
First using performSegue.
class ViewController4PerfomSegue:UIViewController{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
self.performSegueWithIdentifier("showViewController3", sender: nil);
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController3 = segue.destinationViewController as? ViewController3{
viewController3.needBackToRoot();
}
}
}
Second with push manual in your navigation view controller
class ViewController4Push:UIViewController{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
let viewController3 = ViewController3(nibName: "ViewController3", bundle: nil);
viewController3.needBackToRoot();
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
Edit: new way to instantiate from storyboard
class ViewController4Push:UIViewController{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
if let viewController3 = storyboard!.instantiateViewControllerWithIdentifier("ViewController3") as? ViewController3{
viewController3.needBackToRoot();
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
}
Edit: removing when new view was presented
class ViewController4Push:UIViewController, UINavigationControllerDelegate{
#IBAction func pressButtonToPushViewController3(sender:AnyObject?){
if let viewController3 = storyboard!.instantiateViewControllerWithIdentifier("ViewController3") as? ViewController3{
viewController3.needBackToRoot();
self.navigationController?.delegate = self;
self.navigationController?.pushViewController(viewController3, animated: true);
}
}
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
self.navigationController?.delegate = nil;
self.dismissViewControllerAnimated(false, completion: nil);
//or self.removeFromParentViewController();
}
}
I hope help you, if I understand the problem
Edit: after talk in chat with Sinan we resolve it with simple way, just force back present the root element of application
class ViewCustomController:UIViewController{
override func viewDidLoad() {
super.viewDidLoad();
self.hideAndAddNewBackButton();
}
private func hideAndAddNewBackButton(){
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton;
}
func back(sender: UIBarButtonItem) {
if let viewControllerRoot = storyboard!.instantiateViewControllerWithIdentifier("ViewControllerRoot") as? ViewControllerRoot{
self.navigationController?.pushViewController(viewController2, animated: true);
}
}
}
[4] needs to be embedded in a navigation controller. After that, change you #IBAction to use pushViewController:Animated: on the navigationController instead of performSegueWithIdentifier

Resources