How to set image for bar button with swift?
Asked Answered
B

16

71

I am trying to set an Image for bar button Item for that I have an image like:

enter image description here

with resolution 30 * 30 but while I assign this Image to Bar button Its looks like:

enter image description here

I have assigned image this way :

enter image description here

and If I try this way like making an IBOutlet for the button and set Image programatically form this question and code for that is:

 // Outlet for bar button
 @IBOutlet weak var fbButton: UIBarButtonItem!

// Set Image for bar button
var backImg: UIImage = UIImage(named: "fb.png")!
fbButton.setBackgroundImage(backImg, forState: .Normal, barMetrics: .Default)

but nothing happend with this,

Can anybody tell me what I am doing wrong?

or which is the batter way to do this?

Bren answered 16/12, 2014 at 7:58 Comment(0)
B
110

I have achieved that programatically with this code:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //create a new button
        let button: UIButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
        //set image for button
        button.setImage(UIImage(named: "fb.png"), forState: UIControlState.Normal)
        //add function for button
        button.addTarget(self, action: "fbButtonPressed", forControlEvents: UIControlEvents.TouchUpInside)
        //set frame
        button.frame = CGRectMake(0, 0, 53, 31)

        let barButton = UIBarButtonItem(customView: button)
        //assign button to navigationbar
        self.navigationItem.rightBarButtonItem = barButton
    }

    //This method will call when you press button.
    func fbButtonPressed() {

        println("Share to fb")
    }
}

And result will be:

enter image description here

Same way you can set button for left side too this way:

self.navigationItem.leftBarButtonItem = barButton

And result will be:

enter image description here

And if you want same transaction as navigation controller have when you go back with default back button then you can achieve that with custom back button with this code:

func backButtonPressed(sender:UIButton) {
    navigationController?.popViewControllerAnimated(true)
}

For swift 3.0:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //create a new button
        let button = UIButton.init(type: .custom)
        //set image for button
        button.setImage(UIImage(named: "fb.png"), for: UIControlState.normal)
        //add function for button
        button.addTarget(self, action: #selector(ViewController.fbButtonPressed), for: UIControlEvents.touchUpInside)
        //set frame
        button.frame = CGRect(x: 0, y: 0, width: 53, height: 51)

        let barButton = UIBarButtonItem(customView: button)
        //assign button to navigationbar
        self.navigationItem.rightBarButtonItem = barButton
    }

    //This method will call when you press button.
    func fbButtonPressed() {

        print("Share to fb")
    }
}

For swift 4.0:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //create a new button
        let button = UIButton(type: .custom)
        //set image for button
        button.setImage(UIImage(named: "fb.png"), for: .normal)
        //add function for button
        button.addTarget(self, action: #selector(fbButtonPressed), for: .touchUpInside)
        //set frame
        button.frame = CGRect(x: 0, y: 0, width: 53, height: 51)

        let barButton = UIBarButtonItem(customView: button)
        //assign button to navigationbar
        self.navigationItem.rightBarButtonItem = barButton
    }

    //This method will call when you press button.
    @objc func fbButtonPressed() {

        print("Share to fb")
    }
}
Bren answered 10/8, 2015 at 5:53 Comment(2)
Great solution. I don't think you need to cast this as a UIButton let button: UIButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton Actually, in Swift 2.1 we have this: let button: UIButton = UIButton(type: UIButtonType.Custom) – Westley
For swift 4, you need to also add width and height constraint anchors to the button's and set its translatesAutoresizingMaskIntoConstraints as false. eg. button.widthAnchor.constriant(equalToConstant: 53).isActive = true button.heightAnchor.constraint(equalToConstant: 51).isActive = true – Embrasure
B
51

An easy solution may be the following

barButtonItem.image = UIImage(named: "image")

then go to your Assets.xcassets select the image and go to the Attribute Inspector and select "Original Image" in Reder as option.

Burgundy answered 18/4, 2017 at 0:39 Comment(3)
Sometimes the answer is simpler than we think. Previously, I created a new UIBarButtonItem which is initialized w/ the image I was trying to change and assign that to the current UIBarButtonItem. Apparently, you don't have to that. Just set its image property of the current UIBarButtonItem to the image I was trying to change. πŸ€¦πŸ»β€β™‚οΈ. Thanks! – Aft
Also, if the image is not within an assets catalog you can use the UIImage extension .withRenderingMode(.alwaysOriginal) to achieve the same thing. UIImage(named: "image").withRenderingMode(.alwaysOriginal) – Ebonee
This is the simplest answer for this question. It should be the accepted one instead of the overelaborated ones from above. – Eolith
C
21

Similar to the accepted solution, but you can replace the

let button: UIButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton

with

let button = UIButton()

Here is the full solution, enjoy: (it's just a bit cleaner than the accepted solution)

let button = UIButton()
button.frame = CGRectMake(0, 0, 51, 31) //won't work if you don't set frame
button.setImage(UIImage(named: "fb"), forState: .Normal)
button.addTarget(self, action: Selector("fbButtonPressed"), forControlEvents: .TouchUpInside)

let barButton = UIBarButtonItem()
barButton.customView = button
self.navigationItem.rightBarButtonItem = barButton
Chatty answered 5/2, 2016 at 21:18 Comment(4)
add a colon at the end of fbButtonPressed – Kiehl
@AbdulWaheed that's incorrect, because it isn't taking any arguments. – Chatty
You're amazing heidi! – Cloistral
For swift 4, you need to also add width and height constraint anchors to the button's and set its translatesAutoresizingMaskIntoConstraints as false. eg. button.widthAnchor.constriant(equalToConstant: 51).isActive = true button.heightAnchor.constraint(equalToConstant: 31).isActive = true – Embrasure
W
15

Here's a simple extension on UIBarButtonItem:

extension UIBarButtonItem {
    class func itemWith(colorfulImage: UIImage?, target: AnyObject, action: Selector) -> UIBarButtonItem {
        let button = UIButton(type: .custom)
        button.setImage(colorfulImage, for: .normal)
        button.frame = CGRect(x: 0.0, y: 0.0, width: 44.0, height: 44.0)
        button.addTarget(target, action: action, for: .touchUpInside)

        let barButtonItem = UIBarButtonItem(customView: button)
        return barButtonItem
    }
}
Wakerife answered 23/5, 2016 at 15:18 Comment(1)
For swift 4, you need to also add width and height constraint anchors to the button's and set its translatesAutoresizingMaskIntoConstraints as false. eg. button.widthAnchor.constriant(equalToConstant: 44).isActive = true button.heightAnchor.constraint(equalToConstant: 44).isActive = true – Embrasure
A
12

Only two Lines of code required for this

Swift 3.0

let closeButtonImage = UIImage(named: "ic_close_white")
        navigationItem.rightBarButtonItem = UIBarButtonItem(image: closeButtonImage, style: .plain, target: self, action:  #selector(ResetPasswordViewController.barButtonDidTap(_:)))

func barButtonDidTap(_ sender: UIBarButtonItem) 
{

}
Auroraauroral answered 26/7, 2017 at 13:32 Comment(1)
Perfect! Short! and with the proper tint for UIBarButton! – Hers
O
11

I am using latest swift (2.1) and the answer (Dharmesh Kheni and jungledev) does not work for me. The image color was off (when setting in IB, it was blue and when setting directly in UIButton, it was black). It turns out I could create the same bar item with the following code:

let barButton = UIBarButtonItem(image: UIImage(named: "menu"), landscapeImagePhone: nil, style: .Done, target: self, action: #selector(revealBackClicked))
self.navigationItem.leftBarButtonItem = barButton
Olympian answered 22/4, 2016 at 21:2 Comment(0)
B
6

You can use this code for multiple bar button with custom image:

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]

Result will be this:

enter image description here

Bathypelagic answered 7/2, 2018 at 8:3 Comment(2)
self.navigationItem.leftBarButtonItem = nil why this line – Cruz
He must be getting back button <Back. And may be didn't wanted it. – Dews
A
5

Your problem is because of the way the icon has been made - it doesn't conform to Apple's custom tab bar icon specs:

To design a custom bar icon, follow these guidelines:

  • Use pure white with appropriate alpha transparency.
  • Don’t include a drop shadow.
  • Use antialiasing.

(From the guidelines.)

Something that would be possible looks like this. You can find such icons on most free tab bar icon sites.

Button example

Alexina answered 16/12, 2014 at 8:45 Comment(1)
thanks for the reply and can you give me any website where I can download this kind of images? – Bren
E
5

Initialize barbuttonItem like following:

let pauseButton = UIBarButtonItem(image: UIImage(named: "big"),
                                  style: .plain,
                                  target: self,
                                  action: #selector(PlaybackViewController.pause))
Eweneck answered 19/1, 2019 at 0:52 Comment(0)
T
3

Swift 4.

@IBOutlet weak var settingBarBtn: UIBarButtonItem! {
    didSet {
        let imageSetting = UIImageView(image: UIImage(named: "settings"))
        imageSetting.image = imageSetting.image!.withRenderingMode(.alwaysOriginal)
        imageSetting.tintColor = UIColor.clear
        settingBarBtn.image = imageSetting.image
    }
}
Tarahtaran answered 27/6, 2018 at 10:22 Comment(2)
How to use it ? – Protagoras
use like this inside view controller: @IBOutlet weak var profileBarButton: UIBarButtonItem! { didSet { let imageSetting = UIImageView(image: UIImage(named: "staticUserProfile")) imageSetting.image = imageSetting.image!.withRenderingMode(.alwaysOriginal) imageSetting.tintColor = UIColor.clear profileBarButton.image = imageSetting.image } } – Sukkoth
L
2

SwiftUI

.navigationBarItems modifier takes any view you want:

struct ContentView: View {
     var body: some View {
        NavigationView {
            Text("SwiftUI")
            .navigationBarItems(leading:
                HStack {
                    Image(systemName: "trash")
                    Text("Trash")
                }
            )
        }
    }
}

Leading with text[1]

.navigationBarItems(trailing: Image(systemName: "trash") )

Trailing

.navigationBarItems(leading: Image(systemName: "trash.fill"),
                    trailing: Image(systemName: "trash")
)

Bothsides

You can use a button for each if you need an action for each of them.

Lustick answered 20/10, 2019 at 19:42 Comment(0)
T
2

Swift 5+. enter image description here Smooth solution to add ideal image as you desired dynamic Solution

func rightBarButtonItem(iconNameButton: String, selector: Selector) {
    let button = UIButton()
    button.frame = CGRect(x: 0, y: 0, width: 25, height: 25)
    
    button.setImage(UIImage(named: iconNameButton), for: .normal)
    button.addTarget(self, action: selector, for: .touchUpInside)
    button.imageView?.contentMode = .scaleAspectFit

    let buttonBarButton = UIBarButtonItem(customView: UIView(frame: CGRect(x: 0, y: 0, width: 25, height: 25)))
    buttonBarButton.customView?.addSubview(button)
    buttonBarButton.customView?.frame = button.frame

    self.navigationItem.rightBarButtonItem = buttonBarButton
}
Tafilelt answered 30/1, 2022 at 19:20 Comment(0)
U
1

Just choose Original image option when adding an image to assets in Xcode

enter image description here

Unwell answered 19/10, 2020 at 7:57 Comment(0)
M
0

If your UIBarButtonItem is already allocated like in a storyboard. (printBtn)

    let btn = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
    btn.setImage(UIImage(named: Constants.ImageName.print)?.withRenderingMode(.alwaysTemplate), for: .normal)
    btn.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handlePrintPress(tapGesture:))))
    printBtn.customView = btn
Mallissa answered 9/8, 2017 at 3:28 Comment(0)
H
0

If you have set up your UIBarButtonItem with an image in the storyboard, one small hack to change the renderingMode is to add the following code to your viewDidLoad(). This way you don't have to resort to adding the entire button and image in code.

if let navButton = self.navigationItem.leftBarButtonItem, let buttonImage = navButton.image {
    navButton.image = buttonImage.withRenderingMode(.alwaysOriginal)
}
Hennery answered 2/8, 2020 at 22:36 Comment(0)
M
0
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Left",
        style: .plain,target: self, action: #selector(rightbarButtonAction))

navigationItem.rightBarButtonItem?.image = UIImage(named: "Notification Bell")
Maggy answered 14/7, 2022 at 5:6 Comment(0)

© 2022 - 2025 β€” McMap. All rights reserved.