UIButton Extension For UIBarButtonItem - ios

I'm writing an extension by taking a swift file and did codes in following way:
import Foundation
import UIKit
extension UIButton{
func backButtonTarget(_ target: Any, action: Selector) -> UIBarButtonItem {
let backButton = UIButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(12), height: CGFloat(20)))
backButton.setBackgroundImage(UIImage(named: "back.png"), for: .normal)
let barBackButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(target, action: action, for: .touchUpInside)
return barBackButtonItem
}
}
Now, I tried to use it by declaring a button in my viewcontroller where i need that by following way:
var backButton: UIButton! = nil
and in my viewDidLoad I'm declaring the following code:
self.navigationItem.leftBarButtonItem = backButton?.backButtonTarget(self, action: #selector(self.popCurrentViewController))
and in popCurrentViewController
func popCurrentViewController() -> Void {
_ = self.navigationController?.popViewController(animated: true)
}
Here, by declaring above code, UINavigationBar leftbar item button should show as per my created button, but it is not showing neither it enter into the extension function either, but perfectly working on Objective c codes by using category, Where i'm doing wrong/ mistake here ? Any help will be appreciable.
Thanks

There is no button in navigationBar is because your backButton is nil, Currently you have added extension with instance method instead of that you need class method.
extension UIButton {
class func backButtonTarget(_ target: Any, action: Selector) -> UIBarButtonItem {
let backButton = UIButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(12), height: CGFloat(20)))
backButton.setBackgroundImage(UIImage(named: "back.png"), for: .normal)
let barBackButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(target, action: action, for: .touchUpInside)
return barBackButtonItem
}
}
Now add BarButtonItem this way.
self.navigationItem.leftBarButtonItem = UIButton.backButtonTarget(self, action: #selector(self.popCurrentViewController))

Related

Positioning view next to navigationTitle [duplicate]

I am trying to set an Image for bar button Item for that I have an image like:
with resolution 30 * 30 but while I assign this Image to Bar button Its looks like:
I have assigned image this way :
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?
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:
Same way you can set button for left side too this way:
self.navigationItem.leftBarButtonItem = barButton
And result will be:
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")
}
}
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.
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
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
}
}
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)
{
}
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
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:
Initialize barbuttonItem like following:
let pauseButton = UIBarButtonItem(image: UIImage(named: "big"),
style: .plain,
target: self,
action: #selector(PlaybackViewController.pause))
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.
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
}
}
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")
}
)
}
}
}
.navigationBarItems(trailing: Image(systemName: "trash") )
.navigationBarItems(leading: Image(systemName: "trash.fill"),
trailing: Image(systemName: "trash")
)
You can use a button for each if you need an action for each of them.
Swift 5+. 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
}
Just choose Original image option when adding an image to assets in Xcode
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
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)
}
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Left",
style: .plain,target: self, action: #selector(rightbarButtonAction))
navigationItem.rightBarButtonItem?.image = UIImage(named: "Notification Bell")

How can I override this class function?

I have an extension class, where I'm extending UIButton like below, it's working fine.
extension UIButton {
class func backButtonTarget(_ target: Any, action: Selector) -> UIBarButtonItem {
let backButton = UIButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(58), height: CGFloat(15)))
backButton.setTitle("Cancel",for: .normal)
let barBackButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(target, action: action, for: .touchUpInside)
return barBackButtonItem
}
}
But now, I need to change its title for some view controller, so I was thinking of its overriding, but failed. How can be this be overridden, so that I can change its title?
Extensions can not/should not override.
It is not possible to override functionality (like properties or methods) in extensions as documented in Apple's Swift Guide.
Extensions can add new functionality to a type, but they cannot override existing functionality.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html
You can subclass the bar button Item like
class CustomBarButtonItem: UIBarButtonItem {
override func awakeFromNib() {
super.awakeFromNib()
customize()
}
func customize() {
frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(58), height: CGFloat(15))
// Add more as per requirement
}
}
Make title a String parameter for the function, so you can call it and provide a custom title.
class func backButtonTarget(_ target: Any, action: Selector, title: String) -> UIBarButtonItem {
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: 58, height: 15))
backButton.setTitle(title, for: .normal)
let barBackButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(target, action: action, for: .touchUpInside)
return barBackButtonItem
}
}

Eliminate repeated code Swift 3

I have multiple navigation controllers and their root view controllers in my app. I want each navigation bar to have social media buttons closely placed on the right side of the bar. For the same I have used this code to show the buttons in 1 view controller:
let fbImage = UIImage(named: "Facebook.png")!
let twitterImage = UIImage(named: "Twitter.png")!
let youtbImage = UIImage(named:"YouTube.png")!
let fbBtn: UIButton = UIButton(type: .custom)
fbBtn.setImage(fbImage, for: UIControlState.normal)
fbBtn.addTarget(self, action: #selector(HomeViewController.fbBtnPressed), for: UIControlEvents.touchUpInside)
fbBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let fbBarBtn = UIBarButtonItem(customView: fbBtn)
let twitterBtn: UIButton = UIButton(type: .custom)
twitterBtn.setImage(twitterImage, for: UIControlState.normal)
twitterBtn.addTarget(self, action: #selector(HomeViewController.twitterBtnPressed), for: UIControlEvents.touchUpInside)
twitterBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let twitterBarBtn = UIBarButtonItem(customView: twitterBtn)
let youtbBtn: UIButton = UIButton(type: .custom)
youtbBtn.setImage(youtbImage, for: UIControlState.normal)
youtbBtn.addTarget(self, action: #selector(HomeViewController.youtubeBtnPressed), for: UIControlEvents.touchUpInside)
youtbBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let youtbBarBtn = UIBarButtonItem(customView: youtbBtn)
self.navigationItem.setRightBarButtonItems([youtbBarBtn, twitterBarBtn, fbBarBtn], animated: false)
Now I want the same buttons on all navigations bars. I can easily copy this code and respective target methods in viewDidLoad() of each view controller, but too much code is getting repeated. So how can avoid this situation?
I am using Swift 3. I am new to iOS. Any help will be appreciated!
Most duplications are solved by using functions. The first step is to extract that code into a function, the second step is to use the same function from multiple places.
You can add it to an extension, for example:
extension UIViewController {
func addShareButtons() {
...
self.navigationItem.setRightBarButtonItems([youtbBarBtn, twitterBarBtn, fbBarBtn], animated: false)
}
}
and only call
self.addShareButtons()
from every controller that needs the buttons.
You can add button handlers to the extension too.
Another method is to use a UIViewController subclass but that's always a problem if you want to use a UITableViewController subclass.
You can design a custom navigation controller and add these code to the navigation controller. inherit the navigation controller to your storyboard or programmatically where you want to use.
//sample code
class "YourNavigationCorollerName": UINavigationController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
//declare here you code, what you want
}
}
Assuming that these buttons ALWAYS have the same behavior, you can create a custom class for them, and place the repeated code there. For instance:
class FacebookButton : UIButton {
override init() {
super.init()
self.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
self.setImage(UIImage(named: "Facebook.png")!, for: .normal)
}
}
...I think the compiler will yell at you for initializing a UIView without a decoder and frame, but hopefully you get the idea.
To improve on this, you could 1) create a custom UINavigationController with the UIBarButtonItems you want to use, and reuse that controller, and/or 2) create a protocol like the following:
protocol FacebookBtnHandler {
func fbBtnPressed()
}
...and have any relevant VCs conform to it. This would allow you to assign the target and selector for the button in the FacebookButton init method, where you assign the image and frame, and hence prevent repetition of that line, as well.
Try to implement bar button by creating subclass of UIBarButton
class Button: UIBarButtonItem {
convenience init(withImage image : UIImage,Target target: Any, andSelector selector: Any?){
let button = UIButton(type: .custom)
button.setImage(image, for: UIControlState.normal)
button.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
button.addTarget(target, action: selector, for: UIControlEvents.touchUpInside)
self.init(customView: button)
}
}
let fbImage = UIImage(named: "Facebook.png")!
let twitterImage = UIImage(named: "Twitter.png")!
let youtbImage = UIImage(named:"YouTube.png")!
let fbBtn = Button(withImage: fbImage, Target: self, andSelector: #selector(HomeViewController.fbBtnPressed))
let twitterBtn = Button(withImage: fbImage, Target: self, andSelector: #selector(HomeViewController.twitterBtnPressed))
let youtubeBtn = Button(withImage: fbImage, Target: self, andSelector: #selector(HomeViewController.youtubeBtnPressed))
self.navigationItem.setRightBarButtonItems([youtbBarBtn, twitterBarBtn, fbBarBtn], animated: false)
and make it for all your view controller
extension UIViewController {
func addButtons() {
// add above code
}
}

Stuck with adding target to button programmatically

I've created a UIButton and I want it to print some message when it's pressed.
So I did something like this:
In loadView()
button.addTarget(self, action: #selector(ViewController.pressButton(button:)), for: .touchUpInside)
A method:
func pressButton(button: UIButton) {
NSLog("pressed!")
}
But nothing happens when I click the button.
Add the button code in your viewDidLoad and it will work for you:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = UIColor.gray
button.addTarget(self, action: #selector(pressButton(button:)), for: .touchUpInside)
self.view.addSubview(button)
}
func pressButton(button: UIButton) {
NSLog("pressed!")
}
You don´t need to add ViewController.pressButton to selector, it´s enough with the function name.
Swift 4.x version:
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = .gray
button.tag = 0
button.addTarget(self, action: #selector(pressButton(_:)), for: .touchUpInside)
self.view.addSubview(button)
#objc func pressButton(_ button: UIButton) {
print("Button with tag: \(button.tag) clicked!")
}
Swift 5.1 version:
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = .gray
button.tag = 100
button.addTarget(self, action: #selector(pressButton), for: .touchUpInside)
self.view.addSubview(button)
#objc func pressButton(button: UIButton) {
print("Button with tag: \(button.tag) clicked!")
}
try this in Swift3!
button.addTarget(self, action: #selector(self.pressButton(button:)), for: .touchUpInside)
#objc func pressButton(button: UIButton) { NSLog("pressed!") }
Use the following code.
button.addTarget(self, action: #selector(FirstViewController.cartButtonHandler), for: .touchUpInside)
Your class name corresponds to FirstViewController
And your selector corresponds to the following function
func cartButtonHandler() {
}
In swift 3 use this -
object?.addTarget(objectWhichHasMethod, action: #selector(classWhichHasMethod.yourMethod), for: someUIControlEvents)
For example(from my code) -
self.datePicker?.addTarget(self, action:#selector(InfoTableViewCell.datePickerValueChanged), for: .valueChanged)
Just give a : after method name if you want the sender as parameter.
You mention that the addTarget call is in loadView(). Is this in your custom subview, of some kind, or the viewController?
From your selector, it's targeting a method in your ViewController class, but if the target for this action is the view itself, then it would make sense that the action is not going through.
If you declare your button in a viewController, and in viewDidLoad add this target as above, then the message should be printed as you're looking for. I believe you are "targetting" the wrong class with your action.
let cancelButton = UIButton.init(frame: CGRect(x: popUpView.frame.size.width/2, y: popUpView.frame.size.height-20, width: 30, height: 30))
cancelButton.backgroundColor = UIColor.init(patternImage: UIImage(named: cancelImage)!)
cancelButton.addTarget(self, action: #selector(CommentsViewController.canceled), for:.touchUpInside)
Add the button code in override func viewDidLoad() method
Make sure your action handler tagged with #IBAction like this:
#IBAction func pressButton(button: UIButton) {
print("pressed!")
}
Then it will work!

How to set image for bar button with swift?

I am trying to set an Image for bar button Item for that I have an image like:
with resolution 30 * 30 but while I assign this Image to Bar button Its looks like:
I have assigned image this way :
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?
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:
Same way you can set button for left side too this way:
self.navigationItem.leftBarButtonItem = barButton
And result will be:
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")
}
}
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.
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
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
}
}
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)
{
}
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
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:
Initialize barbuttonItem like following:
let pauseButton = UIBarButtonItem(image: UIImage(named: "big"),
style: .plain,
target: self,
action: #selector(PlaybackViewController.pause))
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.
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
}
}
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")
}
)
}
}
}
.navigationBarItems(trailing: Image(systemName: "trash") )
.navigationBarItems(leading: Image(systemName: "trash.fill"),
trailing: Image(systemName: "trash")
)
You can use a button for each if you need an action for each of them.
Swift 5+. 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
}
Just choose Original image option when adding an image to assets in Xcode
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
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)
}
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Left",
style: .plain,target: self, action: #selector(rightbarButtonAction))
navigationItem.rightBarButtonItem?.image = UIImage(named: "Notification Bell")

Resources