NavigationItem Left and Top not showing - ios

I have a view who is called from a Tab Bar controller where i want to have a leftBarButtonItem, a topItem with the logo and a rightBarButtonItem.
On this first view i succeeded to have the topItem with the logo and the rightBarButtonItem, but impossible to have the leftBarButtonItem, programmatically or dragging it in the storyboard.
And i don't understand why. Here is the code.
private func setNavBarItems() {
self.navigationItem.leftBarButtonItem?.image = UIImage(named: "empty-photo-red")
if let navigationBar = self.navigationController?.navigationBar as? SeetyNavigationBar {
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "logo-trans")
imageView.image = image
navigationBar.topItem?.titleView = imageView
}
self.navigationItem.rightBarButtonItem!.image = UIImage(named: "FAQ")
}
If i unwrap leftBarButton with "!" the app crash, so i guess there is no leftBarButton, but why ?
And after when i perform the segue from this view to the next one, i got the leftBarButtonItem and the rightBarButtonItem and the topItem with the logo disappear. I use the same function that i call in my viewDidLoad()
EDIT: For my topItem who was disappearing: self.navigationItem.titleView = imageView
and not navigationBar.topItem?.titleView = imageView solved the problem.

It appears that you did not created any button, before setting the image you have to create the button.
Also for the image that disappear after going the the second screen there is two options, you have your tab bar controller, beneath it you have two views which are linked to your tab bar controller, from there :
you embedded the tab bar controller in a navigation controller (which is not the way to go btw), so to put your buttons, you have to put'em on the parent controller like this for example
// adding right button
let changeLocButton = UIBarButtonItem()
changeLocButton.title = "/!\\"
changeLocButton.action = "AnnotationsStatus:"
changeLocButton.target = self
self.parentViewController?.navigationItem.setRightBarButtonItem(changeLocButton, animated: false)
you embedded each of your two views inside a navigation controller, so you have to create the buttons for EACH view.
// adding right button
let changeLocButton = UIBarButtonItem()
changeLocButton.title = "/!\\"
changeLocButton.action = "AnnotationsStatus:"
changeLocButton.target = self
self.navigationItem.setRightBarButtonItem(changeLocButton, animated: false)
for your image it's the same
- case 1 :
if let navigationBar = self.parentViewController?navigationController?.navigationBar as? SeetyNavigationBar
-case 2 : just copy paste the code with navigation bar in the second view controller

Swift 4.0
let btnBack = UIButton(type: .custom)
btnBack.bounds = CGRect(x: 0, y: 0, width: 44, height: 44)
btnBack.addTarget(self, action: #selector(self.backButtonAction(sender:)), for: .touchUpInside)
btnBack.setImage(#imageLiteral(resourceName: "back_image"), for: .normal)
let leftBarButton = UIBarButtonItem(customView: btnBack)
self.navigationItem.setLeftBarButton(leftBarButton, animated: true)
// Back Button Action
#objc func backButtonAction(sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}

Related

How to push a ViewController from a UIButton that is embedded in Tab Bar Controller

In want to have a button floating next to my Tab Bar. When pressed, this button will open a View that can be Navigated (so a View Controller embedded in a Navigation Controller(?)).
In UITabBarController {
ViewDidLoad() {
super.viewDidLoad()
//I have my 5 tab bar items set up programatically here.
//The middle tab bar item is disabled because the button is on top of it
setupMiddleButton()
}
My setupMiddleButton function
let menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: 52, height: 52))
//..various styling and alignment values...
view.addSubview(menuButton)
menuButton.addTarget(self, action: #selector(menuButtonAction(sender:)), for: .touchUpInside)
finally I've tried to add the code to push the view controller, however I receive nil when tapping the button.
#objc private func menuButtonAction(sender: UIButton) {
let createController = CreateViewController()
let nav3 = UINavigationController(rootViewController: createController)
nav3.navigationController!.pushViewController(createController, animated: true)
I think that you may be passing the wrong parameter to the menuButtonAction function, try to change your code like this:
func setupMiddleButton() {
let menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: 52, height: 52))
//..various styling and alignment values...
view.addSubview(menuButton)
menuButton.addTarget(self, action: #selector(menuButtonAction(_:)), for: .touchUpInside)
}
...
#objc private func menuButtonAction(_ sender: UIButton) {
...
}
So I figured it out. Turns out it was much simpler than I thought, which makes me think I was explaining myself poorly in the question. Anyway, here's the code that worked for me.
let myViewController = ViewController()
let nav = UINavigationController(rootViewController: myViewController)
self.present(nav, animated:true, completion: nil)

navigation bar button and items not showing in swift 3

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

Back Button not visible for custom navigation item added to UIViewController

Displaying an UIViewController modally from one of the View Controllers(which are in a Navigation controller)
code :
self.present(viewController, animated: true, completion: nil)
Within the modal ViewController, a custom Navigation Bar along with navigation item is added. In which, i'm trying to display the Back Button.
let backButton = UIBarButtonItem()
backButton.title = "Back"
self.navigItem.backBarButtonItem = backButton //self.navigItem is the custom Navigation Item
Is there something im missing here?
thanks in advance,
Rajesh
let btnleft : UIButton = UIButton(frame: CGRect(x:0, y:0, width:35,
height:35))
btnleft.contentMode = .center
btnleft.setImage(Set_Local_Image("arrow_left"), for: .normal)
btnleft.addTarget(self, action: #selector(YOUR_ACTION), for: .touchDown)
let backBarButon: UIBarButtonItem = UIBarButtonItem(customView: btnleft)
self.navigationItem.setLeftBarButtonItems([menuBarButon], animated:false)
In Swift3 try this code on the viewDidLoad
self.navigationController?.navigationBar.backIndicatorImage = UIImage(named: "arrow_left")
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "arrow_left")
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -60), for:UIBarMetrics.default)
self.navigationController?.navigationBar.tintColor = UIColor.white
self.navigationItem.hidesBackButton = false

Back UIBarButtonItem appearance remove text and change image

I've watched a lot of questions like this and didn't find an answer for my question.
That how i do now:
APPDELEGATE (didFinishLaunchingWithOptions)
// Text
let barButtonItem = UIBarButtonItem.appearance()
barButtonItem.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: UIControlState.normal)
barButtonItem.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: UIControlState.highlighted)
// Image
let backImage = UIImage(named: "arrow_left"
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
And this almost fit to what i need, but the screen title shifted to the right as there is an invisible back button text. And it definetly is (the root controller's title has 9 characters length):
The question is: How to change image, hide text and keep standart back action for every appearance of back button in ios 9.0 ?
There are three ways to do what you want.
I recommend: Create your own Navigation Class by extending and UINavigationController and override backbuttonItem (UIBarButtonItem) property to customise it according to your requirement. And use the same Navigation Controller class in your project.
Create a custom backBarButton by extending UIBarButtonItem and manually set the same as a back button of default Navigation Controller class, in all view controller.
Hide default navigation bar from root controller and create your own navigation bar using UIView and UIButton in all view controllers. (I always use this choice, that makes customization of navigation bar very easy for me. And I can set my view according to my requirement)
Here is how you can add Custom button for your navigation bar
let btnleft : UIButton = UIButton(frame: CGRect(x:0, y:0, width:35, height:35))
btnleft.contentMode = .center
btnleft.setImage(Set_Local_Image("arrow_left"), for: .normal)
btnleft.addTarget(self, action: #selector(YOUR_ACTION), for: .touchDown)
let backBarButon: UIBarButtonItem = UIBarButtonItem(customView: btnleft)
self.navigationItem.setLeftBarButtonItems([menuBarButon], animated:false)
instead of "arrow_left" You can use any image you want
For Default back action you can create function(YOUR_ACTION) and use in selector of back button
navController.popViewController(animated: true)
I can suggest you 2 options. Both require BaseViewController class as a superclass of all your view controllers.
If you are ok with native back button image, just want to remove back button text you can use this subclass:
class BaseViewController: UIViewController {
var navigationTitle: String = ""
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if !navigationTitle.isEmpty {
navigationItem.title = navigationTitle
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationTitle = navigationItem.title ?? ""
navigationItem.title = ""
}
}
If you want to use your custom icon for back button, you should create UIBarButtonItem with your image, add target, selector, handle action of the button. Sample BaseViewController class below:
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let backImage = UIImage(named: "arrow_left")
navigationItem.hidesBackButton = true
guard let navigationController = navigationController else {
return
}
if navigationController.viewControllers.count > 1 {
// we have to set back button only when we have at least 1 controller to go back
navigationItem.leftBarButtonItem = UIBarButtonItem(image: backImage, style: .plain, target: self, action: #selector(backBarButtonAction(sender:)))
}
}
// MARK: Actions
func backBarButtonAction(sender: UIBarButtonItem) {
navigationController?.popViewController(animated: true)
}
}
According to https://stackoverflow.com/a/16831482/5790492 there is a way to do this without appearance.
Swift 3.0
extension UIViewController {
func setupCustomBackButton() {
if let controllersCount = navigationController?.viewControllers.count, controllersCount > 1 {
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: 12, height: 20))
backButton.setBackgroundImage(UIImage(named: "arrow_left"), for: .normal)
backButton.contentMode = .left
let backButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(self, action: #selector(self.popCurrentViewController), for: .touchUpInside)
navigationItem.leftBarButtonItem = backButtonItem
navigationItem.hidesBackButton = true
}
}
func popCurrentViewController() {
navigationController?.popViewController(animated: true)
}
}
UINavigationBar.appearance().setBackgroundImage(UIImage(), for:
UIBarPosition.any, barMetrics: UIBarMetrics.default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().barTintColor = UIColor.main
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().clipsToBounds = false
UINavigationBar.appearance().backgroundColor = UIColor.main
UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName :
(UIFont(name: "Helvetica", size: 18))!, NSForegroundColorAttributeName:
UIColor.white]
Try this code and make changes accordingly to set image, color and other properties
You should watch Mark Moeykens' youtube series on this. He is IMHO one of the best YouTube presenters for UI Design and implementation in Swift.
The play list is https://www.youtube.com/playlist?list=PLHDMmeIMXj8WyvlX5uFmppVn2Pm0bXVr7
Create an extension for UINavigationItem
extension UINavigationItem {
func backBarButtonItem() -> UINavigationItem {
return UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
}
}

Set UIBarButtonItem target programmatically to previous view Controller

I have two UIViewController (I did not use UINavigationController) which are named as ParentViewController and ChildViewController.
However, I can't add UINavigationBar using storyboard for the child view controller, so I add the UINavigationBar with UIBarButtonItem inside it programmatically.
I've successfully add the navigation bar and the bar button item to the child view controller. The problem I got that I can't set the target for the UIBarButtonItem, so when it pressed, the Parent view controller will show up.
This is the code I use, but I didn't sure where to put them
let navigationBar : UINavigationBar = { //Label to display the text
let navBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
navBar.translatesAutoresizingMaskIntoConstraints = false
let navItem = UINavigationItem(title: "SomeTitle");
let doneItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: nil, action: "selector");
let backItem = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(backAction(_:)));
//let backItem: UIBarButtonItem = backsItem
navItem.rightBarButtonItem = doneItem;
navItem.leftBarButtonItem = backItem;
navBar.setItems([navItem], animated: false);
return navBar;
}();
#IBAction func backAction(_ sender: Any?) {
self.navigationController?.popViewController(animated: true)
}
And then I add the navigationBar to the subView in Child View Controller viewDidLoad()
For your information, I did not do anything in the parent view controller. It just the segue I created on storyboard to show the child view controller when pressed.
please kindly help me...
I already found the solution. Instead of using self.navigationController to show the previous controller, I used the general present command to show the view controller.
This is my code, and it solved all of my problems.
let vc = self.storyboard?.instantiateViewController(withIdentifier: "ParentViewController")
self.present(vc!, animated:true, completion:nil)
I hope it will help the others who facing a problems like me.

Resources