23

I want to display an image in the left hand side of my nav bar in swift.

I have tried adding a nav bar button item and setting an image there.

The problem is that I have to use a really small image for it to fit in the nav bar nicely. But making such a small image leads to pixelation especially on the bigger phone iPhone 6 and 6 Plus.

Is there a way to use a good quality image and then set the frame to fit within the bounds of the nav bar?

My attempt:

var image = UIImage(named: "Harp.png")

image = image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)

self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: UIBarButtonItemStyle.Plain, target: nil, action: nil)
self.navigationItem.leftBarButtonItem.frame = CGRectMake(0, 0, 53, 31)
//image.frame = CGRectMake(0, 0, 53, 31)

I tried putting the frame on the image first and then on the bar button item. But this is throwing up an error:

Type of expression is ambiguous without more context.

2
  • 1
    why not use asset catalogue ? Commented Jul 17, 2015 at 10:50
  • Vinay is right. Using an asset catalogue is easy and automatic. Correct me if I'm wrong but I use @1,@2,@3 the following resolutions: 44x44, 88x88 and 132x132 pixels. ALSO, sometimes I need to correct the size using the image insets (if you have the button in IBuilder you might fix it from there). Commented Dec 13, 2016 at 2:21

6 Answers 6

56

Try This

let button = UIButton(type: UIButtonType.Custom)
button.setImage(UIImage(named: "yourImageName.png"), forState: UIControlState.Normal)
button.addTarget(self, action:Selector("callMethod"), forControlEvents: UIControlEvents.TouchDragInside)
button.frame=CGRectMake(0, 0, 30, 30)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItems = [newBackButton,barButton]

For Swift 3

let button = UIButton.init(type: .custom)
button.setImage(UIImage.init(named: "yourImageName.png"), for: UIControlState.normal)
button.addTarget(self, action:#selector(ViewController.callMethod), for:.touchUpInside)
button.frame = CGRect.init(x: 0, y: 0, width: 30, height: 30) //CGRectMake(0, 0, 30, 30)
let barButton = UIBarButtonItem.init(customView: button)
            self.navigationItem.leftBarButtonItem = barButton

Swift 4

let button = UIButton(type: UIButton.ButtonType.custom)
button.setImage(UIImage(named: "getstarted"), for: .normal)
button.addTarget(self, action:#selector(callMethod), for: .touchDragInside)
button.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItems = [barButton]

Here is action

@objc func callMethod() {   
    //do stuff here
 }
Sign up to request clarification or add additional context in comments.

5 Comments

one issue, the action is not being triggered? I have an action of "tryLogout" and a func tryLogout() but it the logout function is not being triggered?
oh apologies, I see it's just the event type that needs to change
Are you sure the second one is for Swift 3? I recalled that in Swift 3, all the method's parameters will have label. But your button.addTarget(self... doesn't have label for its first parameter.
Worked for me (Swift 3.0). Forgot to set the frame xD
What if i want to add a small text next to the image? for example i want to show how many coins the user have. so i need to show a coins image and the number of coins next to it. how can it be done? thanks.
9

Use this code:

self.navigationItem.leftBarButtonItem = nil

let button = UIButton(type: .custom)
button.setImage(UIImage (named: "ChatTab"), for: .normal)
button.frame = CGRect(x: 0.0, y: 0.0, width: 35.0, height: 35.0)
//button.addTarget(target, action: nil, for: .touchUpInside)
let barButtonItem = UIBarButtonItem(customView: button)

let button2 = UIButton(type: .custom)
button2.setImage(UIImage (named: "ActivityTab"), for: .normal)
button2.frame = CGRect(x: 0.0, y: 0.0, width: 35.0, height: 35.0)
//button.addTarget(target, action: nil, for: .touchUpInside)

let barButtonItem2 = UIBarButtonItem(customView: button2)
self.navigationItem.rightBarButtonItems = [barButtonItem, barButtonItem2]

Output: enter image description here

Comments

5

Swift 5, XCode 11 to make Navigation Bar Item with rounded image, image from assets or to download from URL.

1) New file: UIBarButtonItem+RoundedView.swift

import Foundation

class ImageBarButton : UIView {
    var imageView: UIImageView!
    var button: UIButton!

    convenience init(withUrl imageURL: URL? = nil, withImage image: UIImage? = nil, frame: CGRect = CGRect(x: 0, y: 0, width: 40, height: 40)) {
        self.init(frame: frame)

        imageView = UIImageView(frame: frame)
        imageView.backgroundColor = .white
        imageView.layer.cornerRadius = frame.height/2
        imageView.clipsToBounds = true
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        addSubview(imageView)

        button = UIButton(frame: frame)
        button.backgroundColor = .clear
        button.setTitle("", for: .normal)
        addSubview(button)

        if let url = imageURL { // you can use pods like Nuke or Kingfisher 
         URLSession(configuration: .default).dataTask(with: URL(string: imageUrl)!) {[weak self] (data, response, error) in
          if let data = data , let image = UIImage(data: data) {
              DispatchQueue.main.async {
                self?.imgView.image = image
              }
           }
         }.resume()
        } else if let image = image {
            self.imageView.image = image
        }
    }

    func load()-> UIBarButtonItem {
        return UIBarButtonItem(customView: self)
    }
}

2) Add navigation bar items, you can use navigationItem.rightBarButtonItems, navigationItem.leftBarButtonItems:

private func initalizeNavigationBarItems() {
    let searchBarButtonView = ImageBarButton(withImage: #imageLiteral(resourceName: "greenSearchIcon")) // Assets
    searchBarButtonView.button.addTarget(self, action: #selector(presentSearchViewController), for: .touchUpInside)

    if let user = AccountManager.currentUser, let userProfilePictureURL = user.imageUrl { // API Url
        let profileBarButtonView = ImageBarButton(withUrl: userProfilePictureURL)
        profileBarButtonView.button.addTarget(self, action: #selector(presentMoreViewController), for: .touchUpInside)
        navigationItem.rightBarButtonItems = [searchBarButtonView.load(), profileBarButtonView.load()]
    } else {
        let profileBarButtonView = ImageBarButton(withImage: #imageLiteral(resourceName: "profileIcon"))
        profileBarButtonView.button.addTarget(self, action: #selector(presentMoreViewController), for: .touchUpInside)
        navigationItem.rightBarButtonItems = [searchBarButtonView.load(), profileBarButtonView.load()]
    }
}

@objc func presentMoreViewController(_ sender: Any) {
    // present MoreViewController
}

@objc func presentSearchViewController(_ sender: Any) {
    // present SearchViewController
}

Preview

enter image description here

Comments

4

Swift 4 and 5:

let imageView = UIImageView(image: UIImage(named: "Harp"))
let buttonItem = UIBarButtonItem(customView: imageView)
self.navigationItem.leftBarButtonItem = buttonItem

3 Comments

While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.
@double-beep The accepted answer does none of that. And as you can see it's a poor answer. I will delete my better solution after you read this.
No, you don't need this and I didn't force you to delete your answer. You should better not do it. Of course, code-only solutions are awesome, but solutions with explanations are excellent and take more upvotes.
1

There is a way to use images of different sizes, depending on the device. It's called an Asset Catalog. You'll probably already have one in your project, or if not, you can add one with File > New > File > Resource > Asset Catalogue.

Within your Asset Catalog, you can have multiple 'Image Sets' (these will be shown down the left-hand side). Add a new Image Set with the '+' at the bottom. For each Image Set, you can supply different images (e.g. of different sizes) for each of @1x, @2x, and @3x.

Then, to use one of these images in code, you simply use UIImage(named: "name_of_image_set") - note no extension. The correct image will be loaded, depending on the device.

Hope this helps!

1 Comment

the problem was that the bigger images were extending past the nav bar. Got it sorted with Avijit's solution
1

Swift 5

You need to use constraints to properly set up nav bar button with image.

let button = UIButton(type: .custom)
button.setImage(UIImage(named: yourImageName), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.widthAnchor.constraint(equalToConstant: 40).isActive = true
button.heightAnchor.constraint(equalToConstant: 40).isActive = true
let barButton = UIBarButtonItem(customView: button)
navigationItem.rightBarButtonItem = barButton

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.