implement a simple back button swift ios - ios

I have a navigation bar placed directly on my scene. On his I have a navigation item. I can successfully change title on it.
Now I want a back button to appear - I do not need any customization at present, just the ability to catch the click and default ios look for whatever plaform the app is running (Since Swift that is ios7+).
In viewDidLoad() I have written
outletCatalogNavItem.backBarButtonItem = UIBarButtonItem(title: "test", style .plain, target: self, action: "ownbackNavigationFuncCode");
In *ViewDidAppear()* outletCatalogNavItem.backBarButtonItem is non-nil
Note: I am not using any shared navigation control across scenes in my storyboard - nor wish to at this point since I am porting an app from another tool/language which has its own navigation/stack logic already (meaning I handle switching and navigation myself in code)

Embed your view controller in a UINavigationController. When you push/segue to a new view controller the < Back button you're looking for will appear on the left hand-side.

let backItem = UIBarButtonItem()
backItem.title = "Back"
navigationItem.backBarButtonItem = backItem

Related

How to disable backBarButtonItem? [duplicate]

Is there any official way how to set UIBarButtonItem.enabled property? I tried to set a backButtonItem in previous controller. But enabled property is ignored.
More in this simple example project.
I don't want to some solution like "make your own leftBarButtonItem and set its alpha ..."
Edit: I don't want to hide it, only disable it with dimmed colour and disabled user interaction. It's exactly the same behaviour as for disabled leftBarButtonItem.
As of today it is not possible to disable the back button using the enabled property. The backBarButtonItem property will be nil unless you create a custom item and even then it will ignore the enabled property. There are a couple (non-satisfactory) ways around this.
Hide the button
This is what Apple wants you to do given that they ignore the enabled property. It is as simple as
navigationItem.hidesBackButton = true
and should be the preferred approach unless you have good reasons.
Disable and Tint the Navigation Bar
You can disable user interaction on the whole navigation bar and tint it to make the back button appear disabled.
navigationController?.navigationBar.isUserInteractionEnabled = false
navigationController?.navigationBar.tintColor = UIColor.lightGray
This does, unfortunately, affect other elements in the navigation bar as well so it might not be an option if, for instance, you have another bar button item on the right side.
Use a Custom Left Bar Button Item
The leftBarButtonItem does not ignore the enabled property so you could create a custom item and trigger the pop manually when it is activated.
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(ThisClass.backButtonTapped))
...
navigationItem.leftBarButtonItem?.isEnabled = false
func backButtonTapped() {
self.navigationController?.popViewController(animated: true)
}
This will, however, not have the back bar button style with the leading triangular indicator.
Add below code in your ViewController2.swift Class.
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true;
}
It will hide your back button.
If you want to hide it, UInavigationItem has a hidesBackButton property.
I know this is an old thread, but this may help someone else.
As mentioned by hennes, you can no longer disable the back button. Instead, you will need to disable the entire navigationBar.
The approach I took, was disabling the navigationBar, and then applying an 0.5 alpha to the subviews of the navigation bar.
In your ViewController class:
func changeBarButtons(alpha: CGFloat) {
navigationController?.navigationBar.subviews.forEach { firstViews in
firstViews.subviews.forEach { view in
if ["_UIButtonBarButton", "_UIButtonBarStackView"].contains(type(of: view).description()) {
view.alpha = alpha
}
}
}
}
func set(loading: Bool) {
let alpha: CGFloat = loading ? 0.5 : 1
navigationController?.navigationBar.isUserInteractionEnabled = !loading
changeBarButtons(alpha: alpha)
}
Keep in mind, that Apple could change the names of the class any time. That being said, it's highly unlikely they do so. If you don't mind the title of the View Controller fading out, you can apply the alpha to all the subviews, without checking the class name.
Don't try to disable your custom back button (won't work), just set a new one which is disabled. You can reach the previous navigation item through the UINavigationBar.backItem property.
// set disabled back button
let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItem.Style.plain, target: nil, action: nil)
backButton.isEnabled = false
navigationController?.navigationBar.backItem?.backBarButtonItem = backButton
// disable pop gesture
navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Setting navigationItem title delay issues

When pushing a controller to the navigation stack i execute:
self.navigationItem.title = "";
As i dont want the next view to show the name of the previous controller on the back button.
When i get back to that controller i do this:
override func viewWillAppear(_ animated: Bool) {
self.navigationItem.title = "Title Of View";
...
}
The title is set appropriately but it lags for about 1 second or so.. I remember using this techinique for quite some time without having a problem in the past. The code that sets the titles isn't within a network call or anything like that..
Any ideas about what might be causing this?
In order to hide the back button title you should set empty UIBarButtonItem instance to the self.navigationItem.backBarButtonItem
right after you push the new view controller, like so:
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .done, target: nil, action: nil)
This way you don't have to manipulate the title of the view controller.

How to change Back button text from within the child view controller?

I know that you can set the title of the back button from the IB or in prepareForSegue, but in my app I need to update the title according to events that can happen while the controller is visible.
I tried but nothing happens:
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: title, style: .Plain, target: nil, action: nil)
This works though but has no back arrow:
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: title, style: .Plain, target: nil, action: "popVC")
Any ideas?
The backBarButtonItem is the item used for the back button of the next controller in the navigation stack.
So for example if you have a navigation controller with a root viewController A and you push a viewController B, then the back button title that you see once B is pushed is configured using A.
You could have something like this :
A.navigationItem.backBarButtonItem = UIBarButtonItem(title: "Go back to A", style: .Plain, target: nil, action: nil)
Once B is pushed, you see a back button with "Go back to A".
In your case the tricky part is to find A in the navigation stack from B.
You can do it by searching in the viewControllers of the navigationController like so :
// This code works from the `B` view controller
let viewControllers = self.navigationController?.viewControllers ?? []
if let indexOfCurrent = viewControllers.indexOf(self) where (indexOfCurrent > viewControllers.startIndex) {
let indexOfPrevious = indexOfCurrent.advancedBy(-1)
let previousViewController = viewControllers[indexOfPrevious]
previousViewController.navigationItem.backBarButtonItem?.title = "New Title"
}
Edit
I don't know any clean way to refresh the navigation bar after that. Maybe you could ask a separate question just for that.
What you could do is pop and push the view controller without animation
if let navigationController = self.navigationController {
navigationController.popViewControllerAnimated(false)
navigationController.pushViewController(self, animated: false)
}
Or maybe try to create a new UIBarButtonItem instead of changing the title of the existing one.
try this:
let baritems = self.navigationController?.navigationBar.items
for item in baritems!{
if (item.leftBarButtonItem != nil){
item.title = "123"
}
}
This question is pretty old now, but I was a problem changing the back button text based on a nested tableViewController's selected cell.
It looks like the default back button for a navigationViewController bases its text on the title of the view controller it takes the user back to.
You should probably be careful, as my solution makes a couple assumptions that I'm not positive will always be true.
let vcs = navigationController?.viewControllers
vcs?[(vcs?.count)! - 2].navigationItem.title = "Your Text Here"
Assuming that our current view controller is at the top of the navigation stack -> vcs[vcs.count - 1]; there exists a view controller on that stack before this one -> vcs[vcs.count - 2]; and the navigationItem.title of that preceding view controller can be changed without unwanted side effects; we can change our back button text by changing the navigation title of that preceding view controller.

Selector not working on my swift UIBarButtonItem

I'm writing a to-do list type app, in order to learn swift for iOS development. I had a settings button on the Navigation bar, on the right side, and whenever a person clicked a button on top of the table view, they could add a new item to their list. That causes a "cancel" button to appear on the left side of the bar and a "add" button to appear on the right side. When the person is done, however, those buttons disappear, and so I programatically re-create the settings button, with a call to a function that is supposed to call the segue.
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "modify"), style: UIBarButtonItemStyle.Plain, target: nil, action: Selector("showSettings:"))
This is the code that creates the button on the navbar (and it is indeed created)
func showSettings(sender: AnyObject?) {
print("segueShouldBeDone!")
performSegueWithIdentifier("showSettings", sender: sender)
}
And this is the function that is supposed to call the segue (I added the print to see if it was at least being called, and it isn't).
I've had this same problem in another place in my code, but I had given up on fixing it cause it wasn't that important for me then. But now it is interfering with how the app works, so I wanted to know how to fix it.
Any help would be great.
Your showSettings: selector isn't being called because you specified nil instead of self for the bar button item's target. Change the line to:
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "modify"), style: UIBarButtonItemStyle.Plain, target: self, action: Selector("showSettings:"))
This assume the showSettings: method is in the same class that contains this line of code.
Read the documentation for this initializer, specifically the info about the target parameter.

How to disable back button in navigation bar

Is there any official way how to set UIBarButtonItem.enabled property? I tried to set a backButtonItem in previous controller. But enabled property is ignored.
More in this simple example project.
I don't want to some solution like "make your own leftBarButtonItem and set its alpha ..."
Edit: I don't want to hide it, only disable it with dimmed colour and disabled user interaction. It's exactly the same behaviour as for disabled leftBarButtonItem.
As of today it is not possible to disable the back button using the enabled property. The backBarButtonItem property will be nil unless you create a custom item and even then it will ignore the enabled property. There are a couple (non-satisfactory) ways around this.
Hide the button
This is what Apple wants you to do given that they ignore the enabled property. It is as simple as
navigationItem.hidesBackButton = true
and should be the preferred approach unless you have good reasons.
Disable and Tint the Navigation Bar
You can disable user interaction on the whole navigation bar and tint it to make the back button appear disabled.
navigationController?.navigationBar.isUserInteractionEnabled = false
navigationController?.navigationBar.tintColor = UIColor.lightGray
This does, unfortunately, affect other elements in the navigation bar as well so it might not be an option if, for instance, you have another bar button item on the right side.
Use a Custom Left Bar Button Item
The leftBarButtonItem does not ignore the enabled property so you could create a custom item and trigger the pop manually when it is activated.
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(ThisClass.backButtonTapped))
...
navigationItem.leftBarButtonItem?.isEnabled = false
func backButtonTapped() {
self.navigationController?.popViewController(animated: true)
}
This will, however, not have the back bar button style with the leading triangular indicator.
Add below code in your ViewController2.swift Class.
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true;
}
It will hide your back button.
If you want to hide it, UInavigationItem has a hidesBackButton property.
I know this is an old thread, but this may help someone else.
As mentioned by hennes, you can no longer disable the back button. Instead, you will need to disable the entire navigationBar.
The approach I took, was disabling the navigationBar, and then applying an 0.5 alpha to the subviews of the navigation bar.
In your ViewController class:
func changeBarButtons(alpha: CGFloat) {
navigationController?.navigationBar.subviews.forEach { firstViews in
firstViews.subviews.forEach { view in
if ["_UIButtonBarButton", "_UIButtonBarStackView"].contains(type(of: view).description()) {
view.alpha = alpha
}
}
}
}
func set(loading: Bool) {
let alpha: CGFloat = loading ? 0.5 : 1
navigationController?.navigationBar.isUserInteractionEnabled = !loading
changeBarButtons(alpha: alpha)
}
Keep in mind, that Apple could change the names of the class any time. That being said, it's highly unlikely they do so. If you don't mind the title of the View Controller fading out, you can apply the alpha to all the subviews, without checking the class name.
Don't try to disable your custom back button (won't work), just set a new one which is disabled. You can reach the previous navigation item through the UINavigationBar.backItem property.
// set disabled back button
let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItem.Style.plain, target: nil, action: nil)
backButton.isEnabled = false
navigationController?.navigationBar.backItem?.backBarButtonItem = backButton
// disable pop gesture
navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Resources