Swift UIBarButtonItem add Gesture Recognizer - swift

I want to add a long press Gesture Recognizer to a UIBarButtonItem, but I can't. There is no possibility using the Storyboard, nor is there a method addGestureRecognizer in UIBarButtonItem.
How can I solve this problem?

You can try the following method:
//1. Create A UIButton Which Can Have A Gesture Attached
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 80, height: 40)
button.setTitle("Press Me", for: .normal)
//2. Create The Gesture Recognizer
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(doSomething))
longPressGesture.minimumPressDuration = 1
button.addGestureRecognizer(longPressGesture)
//3. Create A UIBarButton Item & Initialize With The UIButton
let barButton = UIBarButtonItem(customView: button)
//4. Add It To The Navigation Bar
self.navigationItem.leftBarButtonItem = barButton
Of course the Selector method would be replaced with your own method.

Didn't work with UIButton (iOS 12), however works with UILabel:
let backButtonView = UILabel()
backButtonView.isUserInteractionEnabled = true
backButtonView.text = "x"
backButtonView.sizeToFit()
backButtonView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onBackButtonClick(_:))))
backButtonView.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(onBackButtonLongPress(_:))))
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backButtonView)

Related

I am trying to create a UIbarButtonItem whose width and height is equal to 70% of the height of the navigationbar?

I am trying to write an extension fo UIBarButtonItem. I would like to use auto layout so that the UIBarButtonItem's width and height is 70% of the height of the UINavigationBar. When I implement this extension, i am getting the following auto layout errors:
import UIKit
extension UIBarButtonItem {
static func menuButton(target: Any?, action: Selector, imageName: String, navigationBar: UINavigationBar) -> UIBarButtonItem{
let button = UIButton.init(type: .system)
let image = UIImage.init(named: imageName)
button.setBackgroundImage(image, for: .normal)
button.addTarget(target, action: action, for: .touchUpInside)
let menuButton = UIBarButtonItem.init(customView: button)
menuButton.customView?.translatesAutoresizingMaskIntoConstraints = false
menuButton.customView?.widthAnchor.constraint(equalTo: navigationBar.heightAnchor, multiplier: 0.7).isActive = true
menuButton.customView?.heightAnchor.constraint(equalTo: navigationBar.heightAnchor, multiplier: 0.7).isActive = true
return menuButton
}
}
Implementation:
let rightButton = UIBarButtonItem.menuButton(target: self, action: #selector(editCells), imageName: "expand", navigationBar: navigationController!.navigationBar)
navigationItem.rightBarButtonItem = rightButton
Error message in console:
Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutDimension:0x600001be1180 "UIButton:0x7ff5d6d16b80.width"> and <NSLayoutDimension:0x600001be25c0 "UINavigationBar:0x7ff5d911a2f0.height"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'
You can create custom view for your navigationBar custom button and set properties for whatever you want like this:
func addRightButton() {
let barButtonView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 180, height: 40)))
barButtonView.backgroundColor = UIColor.red
let navigationBarHeightWithRatio = (navigationController?.navigationBar.frame.height ?? 100) * 0.7
let customBarButton = UIButton(frame: CGRect(x: 0, y: 8, width: navigationBarHeightWithRatio, height: navigationBarHeightWithRatio))
customBarButton.setImage(UIImage(named: "your_image_name"), for: .normal)
customBarButton.setTitle("title", for: .normal)
customBarButton.addTarget(self, action: #selector("<your_action_function>"), for: .touchUpInside)
barButtonView.addSubview(customBarButton)
let rightBarButton = UIBarButtonItem(customView: barButtonView)
navigationItem.rightBarButtonItem = rightBarButton
}
Note:
You can customize width different width, height values and x, y positions.
I hope it is works.
Enjoy.
The error message is clear. When you say:
let rightButton = UIBarButtonItem.menuButton(
target: self, action: #selector(editCells),
imageName: "expand",
navigationBar: navigationController!.navigationBar)
... and the menuButton method runs, at that moment, you are trying to form a constraint relationship between the button and the navigation bar at a time when the button is not in the navigation bar. That, as the error message tells you, is illegal.
(I doubt that the goal you have outlined is possible at all, but that's another story. I'm just explaining the error message.)

Swift onclick textfield image

I have got a textfield in my Swift code
let PassINP: UITextField = {
let textField = UITextField()
textField.rightViewMode = .always
var imageR = UIImageView(frame: CGRect(x:7,y:4,width:24,height:27))
imageR.image = #imageLiteral(resourceName: "eye")
var paddingR = UIView(frame: CGRect(x: 0, y: 0, width:40, height: 32))
paddingR.addSubview(imageR)
textField.rightView = paddingR
textField.isSecureTextEntry = true
return textField
}()
And i want to call a function when rightView is clicked.How can i achieve that?
I have tried adding this code
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.rightViewTapped))
paddingR.addGestureRecognizer(tapGesture)
But it was not working
For that you need to add TapGesture to rightView of your UITextField.
//Add UITapGestureRecognizer to your PassINP's rightView `viewDidLoad`
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(favoriteButtonPressed))
PassINP.rightView?.addGestureRecognizer(tapGesture)
Now add rightViewTapped method to handle the tap on the rightView
func rightViewTapped(_ gesture: UITapGestureRecognizer) {
print("rightViewTapped")
}

BarButtonItem not appearing

I have a simple + button on the right side to add rows to my tableView, however the button is not appearing. This is how i implement it
let AddButton = UIButton()
AddButton.setTitle("+", forState: .Normal)
let AddView = UIBarButtonItem(customView: AddButton)
self.navigationItem.rightBarButtonItem = AddView
AddButton.addTarget(self, action: #selector(self.addRow), forControlEvents: UIControlEvents.TouchUpInside)
Note, I use the same exact implementation for my hamburger button which does appear. This is the working hamburger button implementation
let navicon = UIButton(type: UIButtonType.System)
navicon.setImage(defaultMenuImage(), forState: UIControlState.Normal)
navicon.frame = CGRectMake(0, 0, 30, 30)
let menu = UIBarButtonItem(customView: navicon)
self.navigationItem.leftBarButtonItem = menu
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
navicon.addTarget(self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)), forControlEvents: .TouchUpInside)
why is this happening?
Try:
let AddButton = UIButton(type: .Custom)
AddButton.frame = CGRectMake(0, 0, 44, 44)

Swift: Programmatically add UIButton above keyboard

I'm trying to add a (custom with a corner radius of 25.0) UIButton to hover just above the keyboard in my view controller.
I have tried accomplishing this on my own by adding this button to a toolbar with the following code, however, I am not looking for a toolbar:
let toolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.frame.size.width, 50))
toolbar.barStyle = UIBarStyle.Default
loginButton.titleLabel?.textColor = UIColor.whiteColor()
loginButton.backgroundColor = UIColor.redColor()
loginButton.titleLabel?.text = "Sign Up"
loginButton.addTarget(self, action: #selector(signUp), forControlEvents: .TouchUpInside)
let customButton = UIBarButtonItem(customView: loginButton)
toolbar.items = [customButton]
toolbar.sizeToFit()
//...
//When credentials are valid, show/enable button...
usernameEmailField.inputAccessoryView = toolbar
How can I add a UIButton to hover just above the keyboard at all times?
Thank you.
This one works for me. Please try this
//create toolbar object
let doneToolBar: UIToolbar = UIToolbar(frame:CGRect(x: 0, y: 0, width: UIScreen.mainScreen().bounds.size.width, height: 44))
doneToolBar.barStyle = UIBarStyle.BlackTranslucent
//add barbuttonitems to toolbar
let flexsibleSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil) // flexible space to add left end side
let doneButton: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: #selector(UITextField.didPressDoneButton))
doneToolBar.items = [flexsibleSpace,doneButton]
//assing toolbar as inputAccessoryView
textField.inputAccessoryView = doneToolBar
doneToolBar.sizeToFit()

Back Button Image - what is it called in Swift?

I am trying to use Swift's internal back button image.
I have asked this question before and got the technically correct answer that it inherits it from the previous View, BUT if I insert this code you can control the back button on the current View.
// Takeover Back Button
self.navigationItem.hidesBackButton = false
let newBackButton = UIBarButtonItem(title: "<", style: .Plain, target: self, action: "segueBack")
navigationItem.leftBarButtonItem = newBackButton
That gives me a <, "ABC" would give me ABC etc but how do I trigger Swift to put up it's internal Back Button image. The code below doesn't work but I would have thought is along the right lines.
let backImg: UIImage = UIImage(named: "BACK_BUTTON_DEFAULT_ICON")!
navigationItem.leftBarButtonItem!.setBackgroundImage(backImg, forState: .Normal, barMetrics: .Default)
Has anyone worked out how to do this?
Try to add custom view as back button like as
var backButton = UIButton(frame: CGRectMake(0, 0, 70.0, 70.0))
var backImage = UIImage(named: "backBtn")
backButton.setImage(backImage, forState: UIControlState.Normal)
backButton.titleEdgeInsets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 0.0)
backButton.setTitle("Back", forState: UIControlState.Normal)
backButton.addTarget(self, action: "buttonPressed", forControlEvents: UIControlEvents.TouchUpInside)
var backBarButton = UIBarButtonItem(customView: backButton)
var spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
spacer.width = -15
self.navigationItem.leftBarButtonItems = [spacer,backBarButton]
It will look same as iOS back button
I struggled with this question for a while. Finally I got the back image with the following code:
let backImage = navigationController?.navigationBar.subviews[2].subviews[0].subviews[0].subviews[0] as! UIImageView).image
Before run the code above, make sure the back button is showing. Then you can save backImage to anywhere you want.
Here is the backImage I got.
Here is my solution:
override func viewDidLoad() {
...
let buttonBack = UIBarButtonItem(image: UIImage(named: "backButton"), style: .plain, target: self, action: #selector(buttonSavePressed(_:)))
self.navigationItem.leftBarButtonItem = buttonBack
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: 24.0, height: 24.0))
let backImage = UIImage(named: "backButton")
backButton.setImage(backImage, for: .normal)
backButton.setTitle("Back", for:.normal)
if #available(iOS 13.0, *) {
backButton.setTitleColor(.link, for: .normal)
} else {
backButton.setTitleColor(.blue, for: .normal)
}
backButton.addTarget(self, action:#selector(buttonSavePressed(_:)), for: .touchUpInside)
let backBarButton = UIBarButtonItem(customView: backButton)
let spacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
spacer.width = -15
self.navigationItem.leftBarButtonItems = [spacer,backBarButton]
}
#objc func buttonBackPressed(_ sender: Any) {
...
}
If you want to get the default back button image, the arrow is a class of type _UINavigationBarBackIndicatorView.
Here follows the hack,
UIImage *imgViewBack ;
for (UIView *view in self.navigationController.navigationBar.subviews) {
// The arrow is a class of type _UINavigationBarBackIndicatorView. This is not any of the private methods, so I think
// this is fine for the AppStore...
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
// Set the image from the Default BackBtn Imageview
UIImageView *imgView = (UIImageView *) view;
if(imgView){
imgViewBack = imgView.image ;
}
}
}
Try this to replace the back button image:
let back_image = UIImage(named: "btn_back")
self.navigationBar.backIndicatorImage = back_image
self.navigationBar.backIndicatorTransitionMaskImage = back_image
If you don't like to have the "Back" title you can add this too:
self.navigationBar.topItem?.title = ""