titleView of Navigation item moved to the left? - swift

I have an app with a left (hamburger) navigationItem.leftBarButtonItem and we've set the titleView to the logo of the company. The problem is that they want the logo next to the hamburger. The hamburger button is set in the Storyboard's ViewController and the logo is programmatically, like this:
let logo = UIImage(named: "logo.png")
let imageView = UIImageView(image:logo)
imageView.frame = CGRect(x: 0, y: 0, width: 120, height: 60)
navigationItem.titleView = imageView
Is there a way to move it to the left?
UPDATE:
Regarding the suggestions to use leftBarButtonItems
I've done this in another UIViewController and the result wasn't as I expected it to be.
Here's the code:
let logo = UIImage(named: "logo")!
let karambaButton = UIBarButtonItem(image: logo, style: .plain, target: self, action: nil)
let backBTN = UIBarButtonItem(image: UIImage(named: "back"), style: .plain, target: navigationController, action: #selector(UINavigationController.popViewController(animated:)))
navigationItem.leftBarButtonItems = [backBTN, logoButton]
And here's the result of it:
(The dark block is the image, I had to cover it up because it's a client)

You can set multiple left bar button items by acessing:
navigationItem.leftBarButtonItems = [barItem1, barItem2]
Same with the right side. :)

You can also set auto layout programmatically.
imageView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = imageView.leadingAnchor.constraint(equalTo: hamburgerButton.trailingAnchor, constant: 10)
let verticalConstraint = newView.centerYAnchor.constraint(equalTo: hamburgerButton.centerYAnchor)
let widthConstraint = newView.widthAnchor.constraint(equalToConstant: 120)
let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 120)
imageView.addConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])

UINavigationItem has a property named leftBarButtonItems.
Put your logo imageView into the customView property of a UIBarItem and size it correctly and you should be all set. Just add it to the the array along with the hamburger button.
edited to add -- try using a custom view, that is:
if let logo = UIImage(named: "logo") {
let imageView = UIImageView(image:logo)
let karambaButton = UIBarButtonItem(customView: imageView)
let backBTN = UIBarButtonItem(image: UIImage(named: "back"), style: .plain, target: navigationController,
action: #selector(UINavigationController.popViewController(animated:)))
navigationItem.leftBarButtonItems = [backBTN, logoButton]
}

Related

I am trying to create a UIbarButtonItem whose width and height is equal to 70% of the height of the navigationbar?

I am trying to write an extension fo UIBarButtonItem. I would like to use auto layout so that the UIBarButtonItem's width and height is 70% of the height of the UINavigationBar. When I implement this extension, i am getting the following auto layout errors:
import UIKit
extension UIBarButtonItem {
static func menuButton(target: Any?, action: Selector, imageName: String, navigationBar: UINavigationBar) -> UIBarButtonItem{
let button = UIButton.init(type: .system)
let image = UIImage.init(named: imageName)
button.setBackgroundImage(image, for: .normal)
button.addTarget(target, action: action, for: .touchUpInside)
let menuButton = UIBarButtonItem.init(customView: button)
menuButton.customView?.translatesAutoresizingMaskIntoConstraints = false
menuButton.customView?.widthAnchor.constraint(equalTo: navigationBar.heightAnchor, multiplier: 0.7).isActive = true
menuButton.customView?.heightAnchor.constraint(equalTo: navigationBar.heightAnchor, multiplier: 0.7).isActive = true
return menuButton
}
}
Implementation:
let rightButton = UIBarButtonItem.menuButton(target: self, action: #selector(editCells), imageName: "expand", navigationBar: navigationController!.navigationBar)
navigationItem.rightBarButtonItem = rightButton
Error message in console:
Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutDimension:0x600001be1180 "UIButton:0x7ff5d6d16b80.width"> and <NSLayoutDimension:0x600001be25c0 "UINavigationBar:0x7ff5d911a2f0.height"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'
You can create custom view for your navigationBar custom button and set properties for whatever you want like this:
func addRightButton() {
let barButtonView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 180, height: 40)))
barButtonView.backgroundColor = UIColor.red
let navigationBarHeightWithRatio = (navigationController?.navigationBar.frame.height ?? 100) * 0.7
let customBarButton = UIButton(frame: CGRect(x: 0, y: 8, width: navigationBarHeightWithRatio, height: navigationBarHeightWithRatio))
customBarButton.setImage(UIImage(named: "your_image_name"), for: .normal)
customBarButton.setTitle("title", for: .normal)
customBarButton.addTarget(self, action: #selector("<your_action_function>"), for: .touchUpInside)
barButtonView.addSubview(customBarButton)
let rightBarButton = UIBarButtonItem(customView: barButtonView)
navigationItem.rightBarButtonItem = rightBarButton
}
Note:
You can customize width different width, height values and x, y positions.
I hope it is works.
Enjoy.
The error message is clear. When you say:
let rightButton = UIBarButtonItem.menuButton(
target: self, action: #selector(editCells),
imageName: "expand",
navigationBar: navigationController!.navigationBar)
... and the menuButton method runs, at that moment, you are trying to form a constraint relationship between the button and the navigation bar at a time when the button is not in the navigation bar. That, as the error message tells you, is illegal.
(I doubt that the goal you have outlined is possible at all, but that's another story. I'm just explaining the error message.)

Navigation Bar don't charge correctly the first time

I am developing an app that contains a login and when logging in for the first time the views that go after logging do not load well the navigation bar, when opening the app for the second time and already with the credentials previously entered, this time if they load well the navigation bar.
Does anyone know why this happens?
my viewWillAppear is like this
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 38, height: 38))
imageView.contentMode = .scaleAspectFit
let image = UIImage(named: "img_header")
imageView.image = image
navigationItem.titleView = imageView
//let image_home = UIImage(named: "ic_home")
//let homeButton = UIBarButtonItem(image: image_home, style: UIBarButtonItemStyle.done, target: self, action: #selector(self.cancelMetod2))
// navigationItem.leftBarButtonItem = homeButton
let color_primary: UIColor = val_colores.hexStringToUIColor(val_colores.colorPrimary)
let color_background_primary: UIColor = val_colores.hexStringToUIColor(val_colores.ColorGrisClaro2)
//icono more
let imagen_more = UIImage (named: "ic_more_menu")!
let buttonMore: UIBarButtonItem = UIBarButtonItem(image: imagen_more, style: UIBarButtonItemStyle.done,target: self, action: #selector(self.moreMetod))
self.navigationItem.rightBarButtonItem = buttonMore
//background color
self.navigationController?.navigationBar.barTintColor = color_primary
//back button color
UIBarButtonItem.appearance().tintColor = color_background_primary
//Since iOS 7.0 UITextAttributeTextColor was replaced by NSForegroundColorAttributeName
//title color
UINavigationBar.appearance().titleTextAttributes = [NSAttributedStringKey.foregroundColor: color_background_primary]
//color in carrier, hour, battery
UINavigationBar.appearance().barStyle = UIBarStyle.black
self.navigationController!.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: color_background_primary]
self.navigationController!.navigationBar.barStyle = UIBarStyle.black
self.navigationController!.navigationBar.tintColor = color_background_primary
}

BarButton Item defaulting to center of navigation bar

Im adding a BarButtonItem to a Navigation Bar. This Navigation Controller and Bar don't come from the storyboard and are instead generated programmatically. An issue I've noticed because of this is that the location any BarButton Items are in the center of the navigation bar. Whether it be a RightBarButton or LeftBarButton, the button always appears in the center of the bar. My suspicion is that the available space for button items is zero, causing the buttons to default to the center location. I've attached my code below. Where does the issue arise from?
Creating navigation controller programmatically:
let popoverContent = Itinerary()
popoverContent.parentController = self
let nav = UINavigationController(rootViewController: popoverContent)
nav.modalPresentationStyle = UIModalPresentationStyle.popover
let popover = nav.popoverPresentationController
popover?.sourceView = self.view
nav.navigationBar.barTintColor = UIColor.init(red: 154/255, green: 203/255, blue: 231/255, alpha: 1)
self.present(nav, animated: true, completion: nil)
Adding the BarButtonItems from inside the Itinerary View:
let button = UIButton.init(frame: CGRect.init(x: 0, y: 0, width: 40, height: 40))
let img = UIImage.init(named: "xbutton")
button.setImage(img, for: UIControlState.normal)
button.imageView?.contentMode = .scaleAspectFit
button.addTarget(self, action: #selector(dismissItin), for: .touchUpInside)
let Barbutton = UIBarButtonItem.init(customView: button)
self.navigationItem.rightBarButtonItem = Barbutton

How can i move a button in a UINavigation bar to the right

im trying to move the right button in my navigation bar to the right to align it with buttons on a table view here is what is currently looks like
i made a button like this:
let allButton = UIButton(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
allButton.layer.borderColor = Constants.AppColor.cgColor
allButton.layer.borderWidth = 1
allButton.layer.backgroundColor = UIColor.white.cgColor
allButton.addTarget(self, action: #selector(selectAllContacts), for: .touchUpInside)
allButton.layer.cornerRadius = 10
and im adding it to my nav bar like this:
navigationItem.rightBarButtonItems = [UIBarButtonItem(customView: allButton), importButton]
I have tried adding image insets, content insets and it doesn't work.
Any idea on what else i can try?
Will this do?
navigationItem.rightBarButtonItem = UIBarButtonItem(
title: "Menu >",
style: .plain,
target: self,
action: #selector( rightNavTap )
)
I was able to solve this by adding
let negativeSpacer:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
negativeSpacer.width = -10
and appending that to my array of buttons
navigationItem.rightBarButtonItems = [negativeSpacer, UIBarButtonItem(customView: allButton), importButton]
If anyone finds a better solution let me know.

Back Button Image - what is it called in Swift?

I am trying to use Swift's internal back button image.
I have asked this question before and got the technically correct answer that it inherits it from the previous View, BUT if I insert this code you can control the back button on the current View.
// Takeover Back Button
self.navigationItem.hidesBackButton = false
let newBackButton = UIBarButtonItem(title: "<", style: .Plain, target: self, action: "segueBack")
navigationItem.leftBarButtonItem = newBackButton
That gives me a <, "ABC" would give me ABC etc but how do I trigger Swift to put up it's internal Back Button image. The code below doesn't work but I would have thought is along the right lines.
let backImg: UIImage = UIImage(named: "BACK_BUTTON_DEFAULT_ICON")!
navigationItem.leftBarButtonItem!.setBackgroundImage(backImg, forState: .Normal, barMetrics: .Default)
Has anyone worked out how to do this?
Try to add custom view as back button like as
var backButton = UIButton(frame: CGRectMake(0, 0, 70.0, 70.0))
var backImage = UIImage(named: "backBtn")
backButton.setImage(backImage, forState: UIControlState.Normal)
backButton.titleEdgeInsets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 0.0)
backButton.setTitle("Back", forState: UIControlState.Normal)
backButton.addTarget(self, action: "buttonPressed", forControlEvents: UIControlEvents.TouchUpInside)
var backBarButton = UIBarButtonItem(customView: backButton)
var spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
spacer.width = -15
self.navigationItem.leftBarButtonItems = [spacer,backBarButton]
It will look same as iOS back button
I struggled with this question for a while. Finally I got the back image with the following code:
let backImage = navigationController?.navigationBar.subviews[2].subviews[0].subviews[0].subviews[0] as! UIImageView).image
Before run the code above, make sure the back button is showing. Then you can save backImage to anywhere you want.
Here is the backImage I got.
Here is my solution:
override func viewDidLoad() {
...
let buttonBack = UIBarButtonItem(image: UIImage(named: "backButton"), style: .plain, target: self, action: #selector(buttonSavePressed(_:)))
self.navigationItem.leftBarButtonItem = buttonBack
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: 24.0, height: 24.0))
let backImage = UIImage(named: "backButton")
backButton.setImage(backImage, for: .normal)
backButton.setTitle("Back", for:.normal)
if #available(iOS 13.0, *) {
backButton.setTitleColor(.link, for: .normal)
} else {
backButton.setTitleColor(.blue, for: .normal)
}
backButton.addTarget(self, action:#selector(buttonSavePressed(_:)), for: .touchUpInside)
let backBarButton = UIBarButtonItem(customView: backButton)
let spacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
spacer.width = -15
self.navigationItem.leftBarButtonItems = [spacer,backBarButton]
}
#objc func buttonBackPressed(_ sender: Any) {
...
}
If you want to get the default back button image, the arrow is a class of type _UINavigationBarBackIndicatorView.
Here follows the hack,
UIImage *imgViewBack ;
for (UIView *view in self.navigationController.navigationBar.subviews) {
// The arrow is a class of type _UINavigationBarBackIndicatorView. This is not any of the private methods, so I think
// this is fine for the AppStore...
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
// Set the image from the Default BackBtn Imageview
UIImageView *imgView = (UIImageView *) view;
if(imgView){
imgViewBack = imgView.image ;
}
}
}
Try this to replace the back button image:
let back_image = UIImage(named: "btn_back")
self.navigationBar.backIndicatorImage = back_image
self.navigationBar.backIndicatorTransitionMaskImage = back_image
If you don't like to have the "Back" title you can add this too:
self.navigationBar.topItem?.title = ""