How to add an action to a UIBarButton programmatically? - ios

I've been creating a small iOS app using Swift just for fun, and I have already decided that I want a notification box (a bell-shaped button you can click on to check if there's any notification), and I also wanted to add the bell-shaped button to every screen.
So, I decided to make a base view controller and have other view controllers inherit it. However, that's when my problem arose; I have no idea how to add an action func for that button. Since I create the bell-shaped button programmatically, I cannot just ^ drag and create a new IBaction.
I found this post: link, but this is for a UIButton, not for a UIBarButton, and it didn't work for me.
Sorry for this long question. Below is a simple, one-sentenced question:
MY PROBLEM
How can I add an action to a UIBarButton programmatically?
UPDATE
Here's my base view controller:
import UIKit
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// add a notification button
let notificationButton = UIBarButtonItem(image: UIImage(systemName: "bell.fill"))
notificationButton.tintColor = .black
self.navigationItem.rightBarButtonItem = notificationButton
}
}
UPDATE2
Here's my new code:
import UIKit
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// add a notification button
let notificationButton = UIBarButtonItem(
image: UIImage(systemName: "bell.fill"),
style: .plain,
target: self,
action: #selector(notificationButtonPressed)
)
notificationButton.tintColor = .black
self.navigationItem.rightBarButtonItem = notificationButton
}
#objc func notificationButtonPressed() {
print("Hello")
}
}

You can pass a target-action pair to the initialiser of UIBarButtonItem:
let barButton = UIBarButtonItem(
image: UIImage(systemName: "bell.fill"),
style: .plain,
target: self, action: #selector(buttonTapped)
)
// somewhere in your view controller:
#objc func buttonTapped() {
// do something when the bar button is tapped
}
See the documentation here.
This is similar to UIButton's addTarget(_:action:for:_) method, if you are familiar with that.

Related

Is UIBarButtonItem no longer supporting accessibilityLabel in iOS 14?

Update: This bug has been fixed in iOS 14.5
I have the following class embedded in a UINavigationController:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let barButton = UIBarButtonItem(title: "Save", style: .plain, target: nil, action: nil)
barButton.accessibilityLabel = "Save meeting"
navigationItem.rightBarButtonItem = barButton
}
}
When running iOS 14.4, the accessibility label is ignored and only the visible title is announced by VoiceOver. However, on iOS 13.7, the accessibility label is correctly used. Has the UIBarButtonItem usage changed or is this an iOS bug?
Screenshot for context:
When I must implement a UIBarButtonItem, I always follow these instructions to be sure that a11y will be stable and completely functional. 👍
I don't know if this situation is a bug or a kind of regression due to the new iOS version but implementing a11y in the navigation bar buttons as customization is a perfect way to encounter no unfortunate surprises even if it looks like a boilerplate solution. 🤓
I've created a blank project with a simple view controller embedded in a navigation controller where a right bar button is displayed as follows:
class NavBarViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var a11yRightBarButton: UIBarButtonItem?
let a11y = UILabel()
a11y.text = "OK"
a11y.sizeToFit()
a11y.isUserInteractionEnabled = true //Mandatory to use the 'tap gesture'.
a11yRightBarButton = UIBarButtonItem(customView: a11y)
let tap = UITapGestureRecognizer(target: self,
action: #selector(validateActions(info:)))
a11yRightBarButton?.customView?.addGestureRecognizer(tap)
a11yRightBarButton?.isAccessibilityElement = true
a11yRightBarButton?.accessibilityTraits = .button
a11yRightBarButton?.accessibilityLabel = "validate your actions"
navigationItem.rightBarButtonItem = a11yRightBarButton
}
#objc func validateActions(info: Bool) -> Bool {
print("hello")
return true
}
}
Your right bar button displays "OK" and VoiceOver reads out "validate your actions" under iOS 14.4 and Xcode 12.4. 😉
Following this rationale, you can use a UIBarButtonItem as supporting the accessibilityLabel property in iOS 14. 🎉
Set accessibility of UIBarButtonItem to true.
let barButton = UIBarButtonItem(title: "Save", style: .plain, target: nil, action: nil)
barButton.accessibilityLabel = "Save meeting"
barButton.isAccessibilityElement = true
navigationItem.rightBarButtonItem = barButton

How to edit the back button (not left button) on navigation bar for the present view controller?

Since left button is a different thing, and like back bar button it doesn't help in navigation to the last page it is coming from, I am not interested in using it. However I want to edit the back button such that it removes default the back indicator image (arrow) and have text value- "Cancel" and it navigates it to the last page it is coming from.
I have tried few things. Some of them reflects in all of the pages in the app unfortunately and not just on the current page. Some don't work at all (needless to say)
self.navigationController?.navigationBar.backIndicatorImage = UIImage()
Your question has two parts:
Changing the text of the back item
Changing the back indicator image
Changing the Title
The back item of a view controller actually belongs to the previous view controller. You can change this in the previous controller's code (ie. the controller you are coming from) with the following code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = "Cancel" // Change to whatever you want
backItem.tintColor = UIColor.red // The color of the text can be changed too if you want
navigationItem.backBarButtonItem = backItem // Will show in the next view controller being pushed
}
Changing the Back Indicator Image
Changing the title as seen above only changes the text ("cancel" in your case), but does not actually change the indicator icon or image. To do this, go into the class for the view controller you are trying to change.
override func viewDidLoad() {
super.viewDidLoad()
// "image" is file you want
self.navigationController?.navigationBar.backIndicatorImage = UIImage(named: "image")
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "image")
}
Create a base navigation controller, you can edit image, text color and font in this way.
class BaseNavigationController: UINavigationController {
init() {
super.init(nibName: nil, bundle: nil)
self.navigationBar.titleTextAttributes = [
NSAttributedStringKey.foregroundColor: color,
NSAttributedStringKey.font: font
]
self.navigationBar.barTintColor = color
if #available(iOS 11, *) {
self.navigationBar.backIndicatorImage = image
self.navigationBar.backIndicatorTransitionMaskImage = image
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
try this:
override func viewDidLoad() {
super.viewDidLoad()
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancel))
navigationItem.leftBarButtonItem = cancelButton
}
#objc func cancel(){
navigationController?.popViewController(animated: true)
}
you can also initialize the UIBarButtonItem with a custom image, and you can also do this in the storyboard you don't have to necessarily use code.

How to customize the navigation back symbol and navigation back text?

This is the back icon and back text now:
But if I want my navigation back like this:
I have tried to set the back to my want icon image:
But it useless.
You can hide back button text in many ways.Try this simple approach.
Step1: Goto your mainstoryBoard and click navigationBar.
Step 2: Goto Attributes Inspector under Navigation Item add a BLANK SPACE in Back Button
Step 3: If you want to change backButton text method is pretty much the same.
Update 1: If you want to use an image as a back button check this link
Update 2:
Method 2: Using custom image as a back button.
Paste below code into your detailVC and set image for your back Button.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Detail VC"
let customButton = UIBarButtonItem(image: UIImage(named: "back"), style: .plain, target: self, action: #selector(backButtonTapped)) //
self.navigationItem.leftBarButtonItem = customButton
}
func backButtonTapped() {
_ = navigationController?.popToRootViewController(animated: true)
}
I am setting back button image in assets catalogue with the 32pixel size.I am not sure about the asset image size.Check with apple doc about the size class.
Output:
Create a new UIBarButton and add it the navigationItem.leftBarButton.
let backButton = UIBarButtonItem(image: UIImage(named:"yourImage"), style: .plain, target: self, action: #selector(yourBackMethod(sender:))
navigationItem.leftBarButtonItem = = backButton
#objc internal func yourBackMethod(sender: AnyObject) {
navigationController.popViewController()
}
Hope this helps.

How change the back button to a custom image in Swift2

Hi,
I'm trying to figure out how to change the back button to a custom image on all ViewControllers. I read though a few questions regarding to this solution, but it was mostly outdated.
I want to change < Back to a stock image I have
I was able to disable to hide the back but that's not my goal my goal is to change the default image to a custom one, I added the custom image to the images.xcassets and that didn't work also I tried to set the System Item to Custom and under Bar Item I selected my image which is image.png, but still didn't work, can someone help me approach this solution? Thanks.
override func viewDidLoad() {
let image: UIImage = UIImage(named: "images")!
self.navigationController?.navigationItem.backBarButtonItem?.image = image
}
override func viewDidAppear(animated: Bool) {
// let backButton = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.Plain, target: navigationController, action: nil)
// navigationItem.leftBarButtonItem = backButton
self.navigationItem.setHidesBackButton(false, animated: false)
}
Instead of doing that you can create your own custom button and assign it to leftBarButtonItem. Try this out
var backBtn = UIBarButtonItem()
let image: UIImage = UIImage(named: "images")!
backBtn.image = image
//set other properties for your button
//set traget and action
self.navigationItem.leftBarButtonItem = backBtn
You can just pop the current view controller in action of the back button.
You can add this in AppDelegate
UIBarButtonItem.appearance().setBackButtonBackgroundImage(UIImage(named: name), forState: .Normal, barMetrics: .Default)
This will set back button through out the app

Drawer like Google material design for iOS

I'd like to implement navigation drawer like Uber into iOS(swift). I'm going to achieve it by using a library, called KYDrawerController. https://github.com/ykyouhei/KYDrawerController
However, it cannot provide toggle button, only slide action. Thought I'd like to to implement toggle button that shows the navigation drawer,I have no idea how to add such a function to the library.
If you know how to add the function to the library, or how to achieve my purpose the other way(such as to use the other libraries), please tell me.
Thank you for your kindness.
Using KYDrawerController it can be implemented as follows:
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = UIColor.whiteColor()
title = "MainViewController"
navigationItem.leftBarButtonItem = UIBarButtonItem(
title: "Open",
style: UIBarButtonItemStyle.Plain,
target: self,
action: "didTapOpenButton:"
)
}
func didTapOpenButton(sender: UIBarButtonItem) {
if let drawerController = navigationController?.parentViewController as? KYDrawerController {
drawerController.setDrawerState(.Opened, animated: true)
}
}
}
https://github.com/ykyouhei/KYDrawerController/tree/master/Example/Code

Resources