I have spent all day trying to figure this out and I'm beyond frustrated.
I have a navigation stack and on each screen, based on the content of the screen, I need to hide/show some of the right bar button items. But no matter what I do, the items are changing on the previous screen on the stack, not on the current screen.
My view controllers are all pushed onto a navigation controller. And each view controller can instantiate another view controller and push onto the navigation stack.
let vc = UnifiedArticleViewController()
navigationController?.pushViewController(vc, animated: true)
I have tried the following:
navigationController?.navigationBar.topItem?.rightBarButtonItems = [arrayOfBarButtonItems]
and:
navigationItem.rightBarButtonItems = [arrayOfBarButtonItems]
as well as a variety of other suggestions I've gotten from various stack overflow suggestions.
I have been able to change the title of screens using:
navigationController?.navigationBar.topItem?.title = "New Title Here"
and that works perfectly. What am I doing wrong?
Set the leftBarButtonItems or rightBarButtonItems from the controller you're wanting to set the button(s) on that is in the navigation controller's view stack.
class ViewController: UIViewController {
override func viewDidLoad() {
let leftButton = UIBarButtonItem(title: "Left", style: .done, target: self, action: #selector(leftButtonPressed(_:)))
self.navigationItem.leftBarButtonItems = [leftButton]
let rightButton = UIBarButtonItem(title: "Right", style: .done, target: self, action: #selector(rightButtonPressed(_:)))
self.navigationItem.rightBarButtonItems = [rightButton]
}
#objc func leftButtonPressed(_ sender: UIBarButtonItem) {
}
#objc func rightButtonPressed(_ sender: UIBarButtonItem) {
}
}
am using navigation bar programmatically in swift, but am not able to show the bar button items in navigation bar,
this is the code what I did
override func viewDidLoad() {
super.viewDidLoad()
let navBar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: 420, height: 65))
self.view.addSubview(navBar)
navBar.backgroundColor = hexStringToUIColor("4DC8BD")
let navigationItem = UINavigationItem()
self.title = "Transport APP"
let btn1 = UIButton(type: .custom)
btn1.setImage(UIImage(named: "Menu1"), for: .normal)
btn1.frame = CGRect(x: 30, y: 30, width: 30, height: 30)
btn1.addTarget(self, action: #selector(HomeViewController.menubuttonclick(_:)), for: .touchUpInside)
let item1 = UIBarButtonItem(customView: btn1)
self.navigationItem.setRightBarButtonItems([item1], animated: true)
}
#IBAction func menubuttonclick(_ sender:UIBarButtonItem )
{
print("this menu button click")
}
I can try many ways but am not getting the results
how to show show bar button item in navigation bar,
You should add UINavigationItem to your UINavigationBar and in item1 need to be added in navitem Look at below code
let navitem = UINavigationItem()
navitem.rightBarButtonItem = item1
navBar.setItems([navitem], animated: true)
Swift 3+: Define the barbutton.
//:: Left bar items
lazy var leftBarItem: Array = { () -> [UIBarButtonItem] in
let btnBack = UIButton(type: .custom)
btnBack.frame = kBAR_FRAME
btnBack.addTarget(self, action: #selector(clickOnBackBtn(_:)), for: .touchUpInside)
let item = UIBarButtonItem(customView: btnBack)
item.tag = 3
return [item]
}()
Add this line into viewDidLoad
self.navigationItem.setLeftBarButtonItems(self.leftBarItem, animated: true)
Bar Button Action
#objc func clickOnBackBtn(_ sender: Any){
}
While the other mentioned solutions definitely work for programmatically defining the navigation item, some would prefer a storyboard solution. I searched for a Swift 4, Xcode 9 storyboard solution and was unable to find one, so I will show my solution.
Here is a screenshot of my storyboard before adding the bar button item.
The issue I was having is that while the Shops tableview is embedded in the navigation controller, and adding a bar button item was no issue; the Employees tableview is pushed via the navigation controller in the didSelectRowAt function.
extension ShopsViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedShop = fetchedResultsController.object(at: indexPath)
let st = UIStoryboardname: "Main", bundle: Bundle.main)
let vc = st.instantiateViewController(withIdentifier: "EmployeeViewController") as! EmployeeViewController
vc.shop = selectedShop
self.navigationController?.pushViewController(vc, animated: true)
}
}
The result is that I could not drag a bar button item from the storyboard. When I tried, the item would end up in the tab bar at the bottom:
I found an article that suggested embedding the second view controller in a navigation controller, but that adds other levels of complexity that I wanted to avoid. The work around I found is to drag a navigation item to the navigation bar area, and then you can add a bar button item with no problems.
Here is the result:
I know there is a lot of debate whether storyboards or programmatic layout is better. While I am still very much a beginning iOS developer and cannot personally speak to that, I am finding that sometimes the storyboard solution fits the problem best. I hope this helps other beginners.
if you've already created UINavigationController() you can set navigation items using self.navigationItem like this (in viewDidLoad function):
self.navigationItem.title = "Transport APP"
self.navigationItem.rightBarButtonItem = item1
but if you need to know how to create UINavigationController() for a view, you can do this in AppDelegate class:
let myView = ... //initial your view controller
let nav = UINavigationController()
nav.viewControlles = [myView]
and then everywhere you need, you should push nav view.
let rightBarButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(dismissVC))
self.navigationItem.rightBarButtonItem = rightBarButton
I am trying to code without using Storyboard or Interface Builder in my project. So, in the need of create a side menu for my app, I want to create a Navigation Bar to give the chance to open the menu by tapping on the left button of my navigation Bar.
This is what I have tried with no success:
override func viewDidLoad() {
super.viewDidLoad()
centerViewController = ViewController()
centerViewController.delegate = self
centerNavigationController = UINavigationController(rootViewController: centerViewController)
let menuButton: UIBarButtonItem = UIBarButtonItem(title: "TMDB", style: .plain, target: centerViewController, action: Selector(("toggleLeftButton")))
centerNavigationController.navigationItem.leftBarButtonItem = menuButton
view.addSubview(centerNavigationController.view)
addChildViewController(centerNavigationController)
centerNavigationController.didMove(toParentViewController: self)
}
My Navigation Bar is not showing any button nor title.
I know that is no longer necessary but still. His lessons are helpfull https://www.youtube.com/watch?v=zS-CCd4xmRY
Solved
The problem was where I was writting the code. It must be instantiated inside the viewController where the NavigationController belongs.
I mean, inside the centerViewController not in his parent as I was doing.
This lines of code:
let menuButton: UIBarButtonItem = UIBarButtonItem(title: "TMDB", style: .plain, target: self, action: Selector(("toggleLeftButton")))
self.navigationItem.leftBarButtonItem = menuButton
Inside the controller ViewController.
EDIT
Reference:
Adding UIBarButtonItem to UINav..Controller
How can I change back button place to right bar button of embedded navigation and change the the icon from < to >?
My suggestion is:
Hide back button:
navigationItem.hidesBackButton = YES
Add a right button with an image arrow:
let backButton = UIBarButtonItem(title: ">", style: .Plain, target: self, action: #selector(backTapped))
navigationItem.rightBarButtonItem = backButton
the action of backTapped will pop the view controller from the navigation controller stack.
Let me know in the comments if this approach can resolve your problem.
I use :
let newView = sabtEnsheabViewController(nibName: "sabtEnsheabViewController", bundle: nil)
self.navigationController?.pushViewController(newView, animated: false)
but it show back button to another view
use this :
let newView = EnsheabSabteNamViewController(nibName: "EnsheabSabteNamViewController", bundle: nil)
self.presentViewController(newView, animated: false, completion: nil)
it doesn't show navigationBar anymore
I use this way for change back button position.
//put this code in viewDidLoad()
navigationItem.hidesBackButton = true
navigationItem.rightBarButtonItem = UIBarButtonItem(title: " > ", style: .done,target: self, action: #selector(addTapped))
//function to handle back navigation
#objc func addTapped(){
navigationController?.popToRootViewController(animated: true)
}
How do you remove the back button text.
Current back button:
< Back
Desired back button:
< AnythingElse
None of these have worked:
self.navigationItem.backBarButtonItem?.title = "Back"
self.backItem?.title = ""
self.navigationController?.navigationBar.backItem?.title = ""
self.navigationItem.backBarButtonItem?.title = ""
self.navigationController?.navigationItem.backBarButtonItem?.title="Back"
self.navigationController?.navigationBar.backItem?.title = ""
self.navigationController?.navigationItem.backBarButtonItem?.title
The back button belongs to the previous view controller, not the one currently presented on screen.
To modify the back button you should update it before pushing, on the view controller that initiated the segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let backItem = UIBarButtonItem()
backItem.title = "Something Else"
navigationItem.backBarButtonItem = backItem // This will show in the next view controller being pushed
}
Swift 3, 4 & 5:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = "Something Else"
navigationItem.backBarButtonItem = backItem // This will show in the next view controller being pushed
}
OR
// in your viewDidLoad or viewWillAppear
navigationItem.backBarButtonItem = UIBarButtonItem(
title: "Something Else", style: .plain, target: nil, action: nil)
You can do it from interface builder as follows:
click on the navigation item of previous view controller
from the attributes inspector set the back button text to whatever you want. Thats it!!
You can put this 3 line of code in the ViewController you want to change the back button title.
In your override func viewDidLoad() {}.
let backButton = UIBarButtonItem()
backButton.title = "My Back Button Title"
self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton
Back-button text is taken from parent view-controller's navigation item title. So whatever you set on previous view-controller's navigation item title, will be shown on current view controller's back button text.
You can just put "" as navigation item title in parent view-controller's viewWillAppear method.
self.navigationItem.title = ""
Another way is to put
self.navigationController?.navigationBar.topItem?.title = ""
in current view controller's viewWillAppear method. This one will cause some other problem if navigation stack is too nested.
If you are using xib file for view controller then do this in your view controller class.
class AboutUsViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = []
setUpNavBar()
}
func setUpNavBar(){
//For title in navigation bar
self.navigationController?.view.backgroundColor = UIColor.white
self.navigationController?.view.tintColor = UIColor.orange
self.navigationItem.title = "About Us"
//For back button in navigation bar
let backButton = UIBarButtonItem()
backButton.title = "Back"
self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton
}
}
The result will be:
I do not know where you have used your methods that you put on your question but I could get the desired result if I use, on my ViewController class (in which I want to change the back button), on viewDidLoad() function, the following line:
self.navigationController?.navigationBar.backItem?.title = "Anything Else"
The result will be:
Before
After
The back button belongs to the previous view controller, not the one currently presented on screen.
To modify the back button you should update it before pushing, add viewdidload :
Swift 4:
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: nil)
You can just modify the NavigationItem in the storyboard
In the Back Button add a space and press Enter.
Note: Do this in the previous VC.
This should work:
override func viewDidLoad() {
super.viewDidLoad()
var button = UIBarButtonItem(title: "YourTitle", style: UIBarButtonItemStyle.Bordered, target: self, action: "goBack")
self.navigationItem.backBarButtonItem = button
}
func goBack()
{
self.navigationController?.popViewControllerAnimated(true)
}
Although it is not recommended since this actually replaces the backButton and it also removed the back arrow and the swipe gesture.
Swift 4.2
If you want to change the navigation bar back button item text, put this in viewDidLoad of the controller BEFORE the one where the back button shows, NOT on the view controller where the back button is visible.
let backButton = UIBarButtonItem()
backButton.title = "New Back Button Text"
self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton
If you want to change the current navigation bar title text use the code below (note that this becomes the default back text for the NEXT view pushed onto the navigation controller, but this default back text can be overridden by the code above)
self.title = "Navigation Bar Title"
Swift 4 - Configure the back button before pushing any view controllers
// if you want to remove the text
navigationItem.backBarButtonItem = UIBarButtonItem()
// if you want to modify the text to "back"
navigationItem.backBarButtonItem = UIBarButtonItem(title: "back", style: .plain, target: nil, action: nil)
There are two ways.
1.In the previousViewController.viewDidLoad()
let backBarBtnItem = UIBarButtonItem()
backBarBtnItem.title = "back"
navigationItem.backBarButtonItem = backBarBtnItem
2.In the currentViewController.viewDidAppear()
let backBarBtnItem = UIBarButtonItem()
backBarBtnItem.title = "back"
navigationController?.navigationBar.backItem?.backBarButtonItem = backBarBtnItem
Reason : the backButton comes from navigationBar.backItem.backBarButtonItem,so the first way is obvious.In currentViewController.viewDidLoad(),we can't obtain the reference of backItem,because in viewDidAppear(),the navigationBar pushed navigationView on its stack.so we can make changes to the backItem in currentViewController.viewDidAppear()
For more details,you can see Document:UINavigationBar
Back button text and color text:
navigationController?.navigationBar.tintColor = .red
navigationController?.navigationBar.topItem?.backButtonTitle = "Hi"
In the viewDidLoad method of the presenting controller add:
// hide navigation bar title in the next controller
let backButton = UIBarButtonItem(title: "", style:.Plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backButton
although these answers fix the problem but this could be some useful
class MainNavigatioController: UINavigationController {
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
// first
let backItem = UIBarButtonItem()
backItem.title = "رجوع"
self.viewControllers.last?.navigationItem.backBarButtonItem = backItem
// then
super.pushViewController(viewController, animated: animated)
}
}
Swift 4
While the previous saying to prepare for segue is correct and its true the back button belongs to the previous VC, its just adding a bunch more unnecessary code.
The best thing to do is set the title of the current VC in viewDidLoad and it'll automatically set the back button title correctly on the next VC. This line worked for me
navigationController?.navigationBar.topItem?.title = "Title"
It works for me. Swift 5
navigationItem.backButtonTitle = ""
This works for Swift 5:
self.navigationItem.backBarButtonItem?.title = ""
Please note it will be effective for the next pushed view controller not the current one on the display, that's why it's very confusing!
Also, check the storyboard and select the navigation item of the previous view controller then type something in the Back Button (Inspector).
Try this... it will work ....
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
self.title = ""
}
The above code will hide the text and show only the back arrow on navigation bar.
Swift 4
In my case the solution was to clear the navigation item of the Master View Controller before move to the Child View Controller. And set it again if it is shown again
MasterController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationItem.title = "Master Title"
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationItem.title = ""
}
And this is how I push a UIViewController and clear the back bar button item in the child controller:
MasterController
let childController = ChildController(collectionViewLayout: UICollectionViewFlowLayout())
childController.navigationItem.backBarButtonItem?.title = ""
navigationController?.pushViewController(childController, animated: true)
Following code can be added to a view controller from where you are pushing view controller in which you want to change back button text
Swift 5
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: nil)
For example:-
ViewController1
ViewController2
Assume we want to update back title of viewcontroller2 and we are pushing viewcontroller2 from viewcontroller1.
then you can use following code:-
let vc2 = storyboard.instantiateViewController(withIdentifier: "ViewController2")
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "your custom back button title", style: .plain, target: self, action: nil)
self.navigationController?.pushViewController(vc2, animated: true)
Set self.title = ""
before self.navigationController?.pushViewController(vc, animated: true).
override func viewWillAppear(_ animated: Bool) {
self.tabBarController?.navigationItem.title = "Notes"
let sendButton = UIBarButtonItem(title: "New", style: .plain, target: self, action: #selector(goToNoteEditorViewController))
self.tabBarController?.navigationItem.rightBarButtonItem = sendButton
}
func goToNoteEditorViewController(){
// action what you want
}
Hope it helps!! #swift 3
If you are pushing a view controller from page view controller page, you cannot update the navigation controller's back button title. To solve this create a delegate back to your parent view controller (you may also be able to traverse the view controller hierarchy back up to the parent).
Furthermore, Back buttons have a character limit. If you exceed that character limit, the system will default to "Back". It will not truncate for you. For example:
backItem.title = "Birthdays/Anniversaries" // Get's converted to "Back".
backItem.title = "Birthdays/Anniversa…" // Fits and shows as is.
for Swift 4.2
let backItem = UIBarButtonItem()
backItem.title = ""
navigationItem.backBarButtonItem = backItem
GOTCHA: If you are having trouble with any of the many-starred suggestions, ensure that you are registering your UITableViewCells in viewDidLoad(), not from init()
Solution checked and work in Swift 5
Below I put few solutions for different cases:
1. Remove text from back button
The best solution to remove text from back button is to add in viewDidLoad():
navigationItem.backBarButtonItem = UIBarButtonItem()
2. Set own text on back button
In case you want to set your own title, do it by setting title of backButton:
let backButton = UIBarButtonItem()
backButton.title = "My Title"
navigationItem.backBarButtonItem = backItem
3. Empty back button on all VC
If you want to create common style in entire app - to have just arrow back without text, create base VC for all your View Controllers:
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.backBarButtonItem = UIBarButtonItem()
}
}
Solution presented above let you customize back button in the future if you want to make some exception later, by adding additional variable and overriding it in specific ViewController, f.ex:
class BaseViewController: UIViewController {
var customBackButtonTitle: String?
override func viewDidLoad() {
super.viewDidLoad()
var backButton = UIBarButtonItem()
if let text = customBackButtonTitle {
backButton.title = text
}
navigationItem.backBarButtonItem = backButton
}
}
There has two of different ways to Implanting that part those are ,
1.
navigationItem.backButtonTitle = "Title Goes Here"
(swift 5)
2.
let backButton = UIBarButtonItem()
backButton.title = "Title Goes Here"
self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton