Swift : Logo on navigation bar along with back button - ios

I want to have the logo of my app followed by the app name on the navigation bar. Along with this, there should be a back button.
Below is a screenshot :
I've tried the code below.
self.navigationItem.setHidesBackButton(false, animated:true);
let imgLogo : UIImage = UIImage(named:"Logo")!
let imgViewLogo : UIImageView = UIImageView(image: imgLogo)
imgViewLogo.frame = CGRectMake(0, 0, 40, 40)
let leftItem:UIBarButtonItem = UIBarButtonItem(customView: imgViewLogo)
self.navigationItem.leftBarButtonItem = leftItem
// App Name set on storyboard at design-time
This places the logo on top of the back button shown below.
How can this be achieved?

You can use custom view for navigationItem.titleView. Create UIView with your logo and a label for UIViewController title and set
navigationItem.titleView = YOUR_CUSTOM_VIEW;

Instead of using .leftBarButtonItem use:
let imgLogo : UIImage = UIImage(named:"Logo")!
let imgViewLogo : UIImageView = UIImageView(image: imgLogo)
imgViewLogo.frame = CGRectMake(0, 0, 40, 40)
let leftItem:UIBarButtonItem = UIBarButtonItem(customView: imgViewLogo)
self.navigationItem.leftBarButtonItems?.append(leftItem)
It will be added along with the system back button

You can find tons of example about it.
In this example I've added also a space to centered well your logo if you needed:
let leftButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "Logo")!, style: UIBarButtonItemStyle.Plain, target: self, action:#selector(MyViewController.leftButtonPress(_:)))
let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
negativeSpacer.width = -5.0 // Left inset to better center your logo
navigationItem.leftBarButtonItems = [negativeSpacer,leftButton]
func leftButtonPress(sender: AnyObject?) {
// do whatever you want when you press back button
}

Related

Is it possible to vertically position a custom UIBarButtonItem?

I have a custom UIBarButtonItem, consisting of a UIImage and a UILabel. Set up as such:
addUsersButton = UIButton()
barButtonView = UIView()
addUsersImage = UIImageView(image: UIImage(named: "add-users")?.withRenderingMode(.alwaysOriginal))
barButtonView.addSubview(addUsersImage)
addUsersLabel = UILabel()
addUsersLabel.text = "Your Table"
addUsersLabel.font = ._8RobotoMedium
addUsersLabel.textColor = .wayDarkGray
addUsersLabel.textAlignment = .center
barButtonView.addSubview(addUsersLabel)
var space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
var rightButtonItem = UIBarButtonItem(customView: barButtonView)
rightButtonItem.width = 30
navigationItem.rightBarButtonItem = rightButtonItem
With constraints like this:
addUsersImage.snp.makeConstraints { make in
make.top.centerX.equalToSuperview()
make.height.equalTo(addUsersImageHeight)
make.width.equalTo(addUsersImageWidth)
}
addUsersLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(addUsersImage.snp.bottom).offset(addUsersLabelHeightOffset)
}
however the actual bar button is sunk about half way into the bottom of the navigation item, and bleeds into the view controller's main view.

UINavigationBar - prefersLargeTitles - How to set image to the left of the title?

The below article shows how to add an image to the right of the navigation title.
https://blog.uptech.team/how-to-build-resizing-image-in-navigation-bar-with-large-title-8ba2e8bcb840
I'd like to add the image to the left of the navigation bar title. To achieve it, I set the leftAnchor instead of the right anchor for the imageView like below.
imageView.leftAnchor.constraint(equalTo: navigationBar.leftAnchor, constant: Const.ImageRightMargin)
The image shows above the navigation bar title, which is not what I'm after. I'd like the image to be on the same line as the title (left of the title).
Note:
I've seen other questions on SO about adding images to the title
view but this question specifically requests information about
adding image to the left of the title. Therefore, this question
is not a duplicate.
I know that I can set a custom title view like below but I do not
want to lose the prefersLargeTitles setting of the navigation bar.
self.navigationItem.titleView = customTitleView
Any help is much appreciated.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let img = UIImage.init(named: "imgName")
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
imgView.image = img!
imgView.contentMode = .scaleAspectFit
let item = UIBarButtonItem.init(customView: imgView)
let negativeSpacer = UIBarButtonItem.init(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
navigationItem.leftBarButtonItems = [negativeSpacer, item]
}
}
The result
If you want to execute a request when you click the image, replace this line
let negativeSpacer = UIBarButtonItem.init(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
with that line
let negativeSpacer = UIBarButtonItem.init(barButtonSystemItem: .fixedSpace, target: self, action: #selector(go))
And place this
#objc func go() {
print("go")
}

Adding a custom navigation bar covering content in screen

I have added a custom navigation bar via storyboard. I was expecting the content on the screen to automatically shift downward. but instead it completely covers content on the top of the screen.. is there a clean line of code that automatically creates that spacing between the navigation bar and the view itself?
You might have heard about Cocpods which i feel is a better way to go for cutsom Navigation bar.
You just need to implement the protocol and give the specifications you need for the Navigation bar
Go through the following cooped
https://cocoapods.org/pods/resizable-navigation-bar
Just call this method from viewDidLoad :
func createNavBar() {
let leftNavigationButton = UIButton()
leftNavigationButton.setImage(UIImage(named: "ic_back.png"), forState: .Normal)
leftNavigationButton.frame = CGRectMake(10, 10, 20, 15)
leftNavigationButton.addTarget(self, action: "onBackButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
let customBarItem = UIBarButtonItem(customView: leftNavigationButton)
self.navigationItem.leftBarButtonItem = customBarItem;
//set TitleAppIcon
let GR = UITapGestureRecognizer(target: self, action: Selector("headerLogoTapAction:"))
let imageView = UIImageView(frame: CGRect(x: 90, y: 0, width: ((UIScreen.mainScreen().bounds.width)/3), height: 40))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "yourimag.png") //or set title
imageView.image = image
imageView.addGestureRecognizer(GR)
imageView.userInteractionEnabled = true
navigationItem.titleView = imageView
}
Hope this gonna help you

Swift Custom NavBar Back Button Image and Text

I need to customise the look of a back button in a Swift project.
Here's what I have:
Here's what I want:
I've tried creating my own UIBarButtonItem but I can't figure out how to get the image to be beside the text, rather than as a background or a replacement for the text.
let backButton = UIBarButtonItem(title: "Custom", style: .Plain, target: self, action: nil )
//backButton.image = UIImage(named: "imageName") //Replaces title
backButton.setBackgroundImage(UIImage(named: "imageName"), forState: .Normal, barMetrics: .Default) // Stretches image
navigationItem.setLeftBarButtonItem(backButton, animated: false)
You can do something like that:
let yourBackImage = UIImage(named: "back_button_image")
self.navigationController?.navigationBar.backIndicatorImage = yourBackImage
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = yourBackImage
self.navigationController?.navigationBar.backItem?.title = "Custom"
Your image will only have one color though
Note: Please remember that the back button belongs to the the source ViewController and not to the destination ViewController. Thus, the modification needs to be done in the source VC, which is reflected to all the view in the navigation controller
Code Snippet:
let backImage = UIImage(named: "icon-back")
self.navigationController?.navigationBar.backIndicatorImage = backImage
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = backImage
/*** If needed Assign Title Here ***/
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
swift 4
In my case, I needed to have only the image of the button, without any text. I hope this will be useful to someone.
let imgBackArrow = UIImage(named: "back_arrow_32")
navigationController?.navigationBar.backIndicatorImage = imgBackArrow
navigationController?.navigationBar.backIndicatorTransitionMaskImage = imgBackArrow
navigationItem.leftItemsSupplementBackButton = true
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: nil)
For iOS 12 you can do
func setNavigationBar() {
self.navigationItem.setHidesBackButton(true, animated:false)
//your custom view for back image with custom size
let view = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
let imageView = UIImageView(frame: CGRect(x: 10, y: 10, width: 20, height: 20))
if let imgBackArrow = UIImage(named: "icn_back_arrow") {
imageView.image = imgBackArrow
}
view.addSubview(imageView)
let backTap = UITapGestureRecognizer(target: self, action: #selector(backToMain))
view?.addGestureRecognizer(backTap)
let leftBarButtonItem = UIBarButtonItem(customView: view ?? UIView())
self.navigationItem.leftBarButtonItem = leftBarButtonItem
}
#objc func backToMain() {
self.navigationController?.popViewController(animated: true)
}
For setting custom back bar button and remove text from back bar button,
FROM STORYBOARD only, without any coding.
RESULT:
For the back button image:
By this tutorial: (but didn't work for me)
UINavigationBar.appearance().backIndicatorImage = UIImage(named: "imageName")
But this stack answer: (worked for me)
var backButtonImage = UIImage(named: "back-button-image")
backButtonImage = backButtonImage?.stretchableImage(withLeftCapWidth: 15, topCapHeight: 30)
UIBarButtonItem.appearance().setBackButtonBackgroundImage(backButtonImage, for: .normal, barMetrics: .default)
And for the font, assuming you want the font to match for the whole navigation bar:(currently in use)
if let font = UIFont(name: "Avenir-Book", size: 22) {
UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName: font]
}
Having a button in Navigation Bar with Image AND Text is quite hard. Especially after they have introduced a new headache with UIBarButtonItem position in iOS 11: iOS 11 - UIBarButtonItem horizontal position
You can make either button with image or a button with text, but not a button with both of those. I even tried two UIBarButtonItems together, one with image and other with text - it still doesn't look good at all and their UIStackView can't be easily accessed for modification.
Unexpectedly I found a plain simple solution:
1) design the button as view in Interface Builder. In my case it is inside target UIViewController and accessible via IBOutlet for simplicity
2) set Leading Space constraint for the image to be negative, you might also want to set view's background color to .clear.
3) use it:
#IBOutlet var backButtonView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let backButton = UIBarButtonItem(customView: self.backButtonView)
self.backButtonView.heightAnchor.constraint(equalToConstant: 44).isActive = true // if you set more than you'll get "Unable to simultaneously..."
self.backButtonView.widthAnchor.constraint(equalToConstant: 75).isActive = true
self.navigationItem.leftBarButtonItem = backButton
}
That's it. No need to use the trick with negative spacer for iOS 10 or the trick with imageInsets for iOS 11 (which works only if you have image and doesn't work for image+text, BTW).
I have tried all the above and all make the custom image without changing the text
The only one worked for me is from this answer
let backBTN = UIBarButtonItem(image: UIImage(named: "Back"),
style: .plain,
target: navigationController,
action: #selector(UINavigationController.popViewController(animated:)))
navigationItem.leftBarButtonItem = backBTN
navigationController?.interactivePopGestureRecognizer?.delegate = self
swift 3
extension UIViewController {
func setBackButton(){
let yourBackImage = UIImage(named: "backbutton")
navigationController?.navigationBar.backIndicatorImage = yourBackImage
navigationController?.navigationBar.backIndicatorTransitionMaskImage = yourBackImage
}
}
This worked for me on iOS 13 using swift 5. Just hide the original back button and add a new navigation left bar button item with an action.
navigationItem.hidesBackButton = true
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "backBtn"), style: .plain, target: self, action: #selector(back(sender:)))
#objc func back(sender: UIBarButtonItem) {
self.navigationController?.popViewController(animated:true)
}
I know it was answered. Here you can set title, image and target.
let view = UIView()
let button = UIButton(type: .system)
button.setImage(UIImage(named: "backArrow_theme"), for: .normal)
button.setTitle("Back to workflow", for: .normal)
button.addTarget(self, action: #selector(onBackButton(_:)), for: .touchUpInside)
button.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: -10)
button.sizeToFit()
view.addSubview(button)
view.frame = button.bounds
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: view)
Just replace the backButton with a custom rightBarButtonItem
let backImage = UIImage(named: "BackBtn")?.withRenderingMode(.alwaysOriginal)
navigationItem.leftBarButtonItem = UIBarButtonItem(image: backImage, style: .plain, target: self, action: #selector(popnav))
#objc func popnav() {
self.navigationController?.popViewController(animated: true)
}
Just in case someone need to change all Back buttons color or font with Swift5. UIBarButtonItem.appearance().tintColor = .red
Add this to AppDelegate.swift file.
import UIKit
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIBarButtonItem.appearance().tintColor = .white
UIBarButtonItem.appearance().setTitleTextAttributes([
NSAttributedString.Key.foregroundColor: .red,
NSAttributedString.Key.font: UIFont(name: "font_name", size: 14)!
], for: .normal)
return true
}
}
iOS13 And Later, Try to use UINavigationBarAppearance
let appearance = UINavigationBarAppearance()
// set back image
appearance.setBackIndicatorImage(UIImage(named: "back_icon"), transitionMaskImage: UIImage(named: "back_icon"))
// set appearance to one NavigationController
let navVC = UINavigationController()
navVC.navigationBar.standardAppearance = appearance
navVC.navigationBar.scrollEdgeAppearance = appearance
// or you can config for all navigation bar
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
back title base on you Viewcontroller
viewController.navigationItem.backButtonTitle = "your back title"
Swift 4.2
Add this functions ViewController
func addNavigationBarButton(imageName:String,direction:direction){
var image = UIImage(named: imageName)
image = image?.withRenderingMode(.alwaysOriginal)
switch direction {
case .left:
self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style:.plain, target: nil, action: #selector(goBack))
case .right:
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, style:.plain, target: nil, action: #selector(goBack))
}
}
#objc func goBack() {
navigationController?.popViewController(animated: true)
}
enum direction {
case right
case left
}
Using you should use here
viewDidLoad()
addNavigationBarButton(imageName: "ic_back", direction:.left)
Changing the navigation controller`s standardAppearance or scrollEdgeAppearance will reset your custom backIndicatorImage and backIndicatorTransitionMaskImage
let backImage = UIImage(systemName: "chevron.left.circle.fill")
navigationController?.navigationBar.backIndicatorImage = backImage
navigationController?.navigationBar.backIndicatorTransitionMaskImage = backImage
// this will cause the backIndicatorImage to be reset
let standardAppearance = UINavigationBarAppearance()
navigationController?.standardAppearance = standardAppearance
To change the backIndicatorImage in conjunction with UINavigationBarAppearance you will need to set the backImage using this:
navigationController?.standardAppearance.setBackIndicatorImage(backImage, transitionMaskImage: backImage)
You can change it globally in the AppDelegate with the following code:
UINavigationBar.appearance().backIndicatorImage = UIImage(named: "custom-back")
UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "custom-back")

Adding a logo in Navigation Bar that is left aligned

I have been stumped on how to get an image in a NavigationBar that is left aligned. I understand how to replace the title in the center.
Basically, I have a view controller embedded in a Navigation Bar Controller. In that view controller, I have a search form in the middle and a bar button on the right and I am trying to fit in a logo that is an image to the left side.
Below is the what I understand how to put an image but how do I get it left aligned?
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "imageName")
imageView.image = image
navigationItem.titleView = imageView
You can assign an array of items to the leftBarButtonItems property of the navigationBar. You should add an array because there is usually no space between the left side and the logo, and this doesn't look great. Here is an example:
func setUpUI() {
let logoImage = UIImage.init(named: "logoImage")
let logoImageView = UIImageView.init(image: logoImage)
logoImageView.frame = CGRectMake(-40, 0, 150, 25)
logoImageView.contentMode = .ScaleAspectFit
let imageItem = UIBarButtonItem.init(customView: logoImageView)
let negativeSpacer = UIBarButtonItem.init(barButtonSystemItem: .FixedSpace, target: nil, action: nil)
negativeSpacer.width = -25
navigationItem.leftBarButtonItems = [negativeSpacer, imageItem]
}
The negative spacer to the left of it will push it over a bit, and you can adjust it from there.
For iOS 11 we need to add constraints to the image view of the BarButtomItem
func addLeftBarIcon(named:String) {
let logoImage = UIImage.init(named: named)
let logoImageView = UIImageView.init(image: logoImage)
logoImageView.frame = CGRect(x:0.0,y:0.0, width:60,height:25.0)
logoImageView.contentMode = .scaleAspectFit
let imageItem = UIBarButtonItem.init(customView: logoImageView)
let widthConstraint = logoImageView.widthAnchor.constraint(equalToConstant: 60)
let heightConstraint = logoImageView.heightAnchor.constraint(equalToConstant: 25)
heightConstraint.isActive = true
widthConstraint.isActive = true
navigationItem.leftBarButtonItem = imageItem
}
All the best
Per #Warrior's answer,
For Objective-C, iOS11+ and relative layout for the logo.
// create Youtube icon imageView
UIImageView *youtubeImageView = [[UIImageView alloc] init];
youtubeImageView.translatesAutoresizingMaskIntoConstraints = false;
youtubeImageView.contentMode = UIViewContentModeScaleAspectFit;
youtubeImageView.image = [UIImage imageNamed:#"youtube_icon"];
UIBarButtonItem *imageItem = [[UIBarButtonItem alloc] initWithCustomView:youtubeImageView];
// set constraints
float width = self.view.frame.size.width * 0.3;
float height = width * 178 / 794; // width * 1/ratio
[youtubeImageView.widthAnchor constraintEqualToConstant:width].active = true;
[youtubeImageView.heightAnchor constraintEqualToConstant:height].active = true;
self.navigationItem.leftBarButtonItem = imageItem;
Create a BarButton item with Image.
Assign it as Left Bar Button Item to Navigation Bar as follows.
Objective C
UIBarButtonItem *logo = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:"imageName"] style:UIBarButtonItemStylePlain target:self action:#selector(methodName)];
self.navigationItem.leftBarButtonItem = logo;
SWIFT
let logo = UIBarButtonItem(image: UIImage (named: "imageName"), style: UIBarButtonItemStyle.plain, target: self, action: methodName)
self.navigationItem.leftBarButtonItem = logo
Hope it helps..

Resources