Dismiss Keyboard And Allow Button Gesture Recognizers Swift iOS - ios

I'm using this code to hide the keyboard when the user taps anywhere on the screen outside of the TextView:
override func viewDidLoad() {
super.viewDidLoad()
//Looks for single or multiple taps.
let tap = UITapGestureRecognizer(target: self, action: #selector(UIInputViewController.dismissKeyboard))
tap.delegate = self
//Uncomment the line below if you want the tap not not interfere and cancel other interactions.
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
//Calls this function when the tap is recognized.
#objc func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view is UIButton {
return false
}
return true
}
The problem is I have a UIButton in this view as well - when I tap on the button, the button's gesture recognizer function is not called. Instead, dismissKeyboard is called. I already tried the suggestion of using tap.cancelsTouchesInView = false as well as the shouldReceive method, but neither of them work - in the shouldReceive method, when I tap on the button, the class of touch.view is UIView.
Does anybody know how to allow the user to hide the keyboard when clicking anywhere on screen, but also allow button action handlers to execute?

I fixed this using the following code:
I detect the location of the user's touch
I check if the touch is in the frame of each of the two buttons in my UIView
If this is true, I manually call the button handler and return false from the method
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let view = self.view as? MyViewControllersView {
let location = touch.location(in: self.view)
if view.saveButton.frame.contains(location) {
view.saveHit()
return false
} else if view.scanButton.frame.contains(location) {
view.scanHit()
return false
}
}
return true
}

it works for me, please check out
//MARK:- View Lyfe cycle
override func viewDidLoad() {
super.viewDidLoad()
IQKeyboardManager.shared().isEnableAutoToolbar = false
// IQKeyboardManager.shared().disabledToolbarClasses = self
IQKeyboardManager.shared().isEnabled = false
self.keyboardWillShowAndHide()
initializeHideKeyboard()
}
//MARK:- KayBoard Handling...
//MARK:- Init Hide KeyBoard...
func initializeHideKeyboard(){
//Declare a Tap Gesture Recognizer which will trigger our dismissMyKeyboard() function
let tap: UITapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: #selector(dismissMyKeyboard))
//Add this tap gesture recognizer to the parent view
view.addGestureRecognizer(tap)
}
//MARK:- Dismissing Keyboard...
#objc func dismissMyKeyboard(){
//endEditing causes the view (or one of its embedded text fields) to resign the first responder status.
//In short- Dismiss the active keyboard.
view.endEditing(true)
}
//MARK:- Kayboard Hide and Show...
func keyboardWillShowAndHide(){
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow),
name: UIResponder.keyboardWillShowNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboarddidHide),
name: UIResponder.keyboardWillHideNotification,
object: nil
)
}
//MARK:- KeyBoard Will Show
#objc func keyboardWillShow(_ notification: Notification) {
self.arrConversationList.count
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
self.ChatBottomConstraint.constant = keyboardHeight - self.bottomLayoutGuide.length
DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: {
if self.arrConversationList.count > 0 {
let indexPath = NSIndexPath(row: self.arrConversationList.count-1, section: 0)
self.ConversationTblref.scrollToRow(at: indexPath as IndexPath, at: .bottom, animated: true)
}
})
self.tableviewbottomconstraintref.constant = 0
ConversationTblref.reloadData()
}
}
//MARK:- KeyBoard Will Hide
#objc func keyboarddidHide(_ notification: Notification) {
self.tableviewbottomconstraintref.constant = 0
self.ChatBottomConstraint.constant = 0
ConversationTblref.reloadData()
}
//MARK:- View Disappear for handleing kayboard...
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
IQKeyboardManager.shared().isEnableAutoToolbar = true
IQKeyboardManager.shared().isEnabled = true
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewDidDisappear(_ animated: Bool) {
}

Related

Th Keyboard does not show up when I press a button once, but when I press a button for a long time

I add a click on uitextfield, the keyboard does not show when touched only with a long press in the field.
What can I do to make the keyboard pop up when I press it and I won't hold it for a long time?
TAP TAP works and deletes other views as well ...
What am I doing wrong?
class DeparturesView: UIViewController {
…
private let searchTextFieldData: UISearchTextField = {
let searchTextFieldData = UISearchTextField()
searchTextFieldData.translatesAutoresizingMaskIntoConstraints = false
searchTextFieldData.keyboardType = .alphabet
searchTextFieldData.borderStyle = .roundedRect
searchTextFieldData.autocorrectionType = .no
searchTextFieldData.spellCheckingType = .no
searchTextFieldData.layer.cornerRadius = 10
searchTextFieldData.backgroundColor = .white
searchTextFieldData.returnKeyType = .search
return searchTextFieldData
}()
}
override func viewDidLoad() {
…
//Mark - Add gesture to app
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == self.view
}
//Mark - Hide keyboard
let hideKeyboards = UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:)))
hideKeyboards.delegate = self
view.addGestureRecognizer(hideKeyboards)
//Mark - Detele other view and show keyboard
let hideTableView = UITapGestureRecognizer(target: self, action: #selector(tapHandler))
hideTableView.numberOfTapsRequired = 1
hideTableView.delegate = self
searchTextFieldData.addGestureRecognizer(hideTableView)
}
#objc func tapHandler(_ sender: UITapGestureRecognizer){
print("Show tap tap")
favouriteLabel.removeFromSuperview()
tableViewWithFavouriteBusStop.removeFromSuperview()
}
extension DeparturesView: UITextFieldDelegate{
func textFieldDidBeginEditing(_ textField: UITextField) {
becomeFirstResponder()
}
Follow staps
Remove "hideTableView" TapGesture
add self.earchTextFieldData.delegate = self in viewDidLoad and
replace "textFieldDidBeginEditing"
func textFieldDidBeginEditing(_ textField: UITextField) {
favouriteLabel.removeFromSuperview()
tableViewWithFavouriteBusStop.removeFromSuperview()
becomeFirstResponder()
}

Clicking button hides keyboard and doesnt hit the action when keyboard is up

I am using the following code to raise the keyboard when I click on a UITextField.
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
self.hideKeyboardWhenTappedAround()
Here is the extension I am using.
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
The problem I have having is when the keyboard is up, it puts the one main button (the search button) unclickable. If I click this button, it just lowers the keyboard, then I have to click it again.
How can this be fixed?
What I did to solve this issue with one of my project was to listen to the gesture recognizer. If the element being actioned is a button I don't perform the action.
firstly, assign the delegate of your tapGesture recognizer
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
tap.delegate = self // assign the delegate to the viewcontroller/who ever you assigned to conform to the UIGestureRecognizerDelegate
view.addGestureRecognizer(tap)
}
Conform to UIGestureRecognizerDelegate and use the function shouldReceive touch to decide what action to take. To fix your issue, if a user taps on a button we just don't perform the gesture.
extension UIViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return !(touch.view is UIButton)
}
}
caveat of this, is that if you do perform the button action instead of the gesture you need to implement/call the dismiss keyboard method after the button performs it process.

Dismiss keyboard in iOS

I looked at and tried multiple solutions for Swift 3, Xcode 8 but couldn't get any to work. I've tried:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
and also setting a text field input as first responder:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
pressureInput.resignFirstResponder()
}
I don't know if something from Xcode 8 to Xcode 9 that cause these methods to not work, or if I messed elsewhere. I have 9 text fields and they've all set delegate to self. Their tags are incremented to move on to the next text field on pressing return. Don't think that would affect it. Sorry, new at this! The code runs fine with either of those attempted functions, but they keyboard stays. I would just like to dismiss keyboard when touched outside of any text field.
first of all write this extension in any swift file
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
view.endEditing(true)
}
}
Than in viewDidLoad of that View only call in any view controller there are textFields.
self.hideKeyboardWhenTappedAround()
Swift 4, 5. I always use hide keyboard when tapped around and return button.
override func viewDidLoad() {
super.viewDidLoad()
hideKeyboardWhenTappedAround()
emailTextField.delegate = self // your UITextfield
passwordTextField.delegate = self // your UITextfield
}
// Hide Keyboard
extension EmailAutorization: UITextFieldDelegate {
// Return button tapped
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// Around tapped
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(EmailAutorization.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
Here is Solution of Dismiss Keyboard and Move View Up on Keyboard Open : Swift 5
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(taped))
view.addGestureRecognizer(tap)
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(KeyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
//This Method Will Hide The Keyboard
#objc func taped(){
self.view.endEditing(true)
}
#objc func KeyboardWillShow(sender: NSNotification){
let keyboardSize : CGSize = ((sender.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size)!
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
#objc func KeyboardWillHide(sender : NSNotification){
let keyboardSize : CGSize = ((sender.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size)!
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
Did you tried to debug the program to see if the code stops in the function at all(with break point)? Usually this code should work...Check if those textFields are in the super view or in a child view and if they are maybe you should call self.childView.endEditing(true).
If you really work with multiple textFields maybe you should try IQKeyboardManager library. I use it in all my projects. You can find it here: https://github.com/hackiftekhar/IQKeyboardManager. Simple to use and with good support. Just install it trough cocoa pods, put IQKeyboardManager.sharedManager().enable = true in the AppDelegate and you're ready to go. :)
Are you sure that touchesBegan is being called? If you're sure, try adding self.resignFirstResponder() to your touchesBegan function. This tells your view controller that it's no longer the first responder and should dismiss the keyboard.
If not, what you'll want to do is create a UITapGestureRecognizer, add it to your view, and wire it to a function that calls self.resignFirstResponder().

UITapGestureRecognizer breaks UITableView didSelectRowAtIndexPath in SearchField Class in Swift?

I am using this library for SearchText Field
https://github.com/apasccon/SearchTextField
Here is my Code :
override func viewDidLoad() {
super.viewDidLoad()
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: Selector("dismissKeyboard")))
}
func dismissKeyboard()
{
ClientList.resignFirstResponder()
self.view.endEditing(true)
}
Dismiss of keyboard is working but the didSelectRowAtIndexPath is not getting called so i am not able to select anything
Image for Reference :
Partial Solution I Done:
func hideKeyboard(gestureRecognizer: UIGestureRecognizer) {
let point = gestureRecognizer.locationInView(ClientList.tableView)
let indexPath = ClientList.tableView!.indexPathForRowAtPoint(point)
if indexPath != nil {
return
}
if ClientList.becomeFirstResponder() {
ClientList.resignFirstResponder()
}
}
But now issue is i have other list too , how can i implement for other list ?
You can solve this issue like this
ViewDidLoad
self.tap = UITapGestureRecognizer(target: self, action: "viewTapped:")
self.tap.delegate = self
self.view.addGestureRecognizer(self.tap)
Function
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view != nil && touch.view!.isDescendantOfView(self.tableView) {
return false
}
return true
}
Who's the target of the gesture? I think it should be the list since it is what you tap and it is above the view
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
Add this to viewDidLoad
And add this function
func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}

Gesture Recognizer Not Called

I have set up a gesture recognizer for dismissing the keyboard when the user taps outside the textfield. DismissKeyboard function does not get called.
Have I set up the observer wrong or is this a different issue? Also, this is a tableview that is being tapped.
Code Excerpt
class CommentsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("keyboardWillShow:"),
name: UIKeyboardWillShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("keyboardWillHide:"),
name: UIKeyboardWillHideNotification,
object: nil)
}
func keyboardFrameChanged(notification: NSNotification) {
println("keyboardFrameChanged")
let userInfo = notification.userInfo
let key = UIKeyboardFrameEndUserInfoKey
if let info = userInfo {
let frameValue = info[key] as! NSValue
let _frame = frameValue.CGRectValue()
}
}
func keyboardWillShow(notification: NSNotification) {
if keyboardDismissTapGesture == nil
{
println("dismiss")
keyboardDismissTapGesture = UITapGestureRecognizer(target: self, action: Selector("dismissKeyboard:"))
self.view.addGestureRecognizer(keyboardDismissTapGesture!)
}
}
func keyboardWillHide(notification: NSNotification) {
if keyboardDismissTapGesture != nil
{
println("test2")
self.view.removeGestureRecognizer(keyboardDismissTapGesture!)
keyboardDismissTapGesture = nil
}
}
func dismissKeyboard(sender: AnyObject) {
println("dismiss keyboard")
commentTextField.resignFirstResponder()
}
I set a breakpoint at dismissKeyboard, but it doesn't even get called.
Output
When I tap the textview and the keyboard opens, this is the output
keyboardFrameChanged
keyboardFrameChanged
will show
dismiss
When I tap anything else (trying to dismiss the keyboard), no further outputs.
Set the gesture recognizer delegate to yourself and add the UIGestureRecognizerDelegate protocol.
func keyboardWillShow(notification: NSNotification) {
if keyboardDismissTapGesture == nil
{
println("dismiss")
keyboardDismissTapGesture = UITapGestureRecognizer(target: view, action: "dismissKeyboard:")
keyboardDismissTapGesture.delegate = self
self.view.addGestureRecognizer(keyboardDismissTapGesture!)
}
}
Then add:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
My guess is, the gesture of your table view is interfering with the new UITapGesture. Try this solution or else you should fail the gesture of your table view when your new UITapGesture is detected.
To fail the UITapGestureRecognizer of the table view I use this code:
if let recognizers = yourTableView.gestureRecognizers, let index = find(recognizers.map { $0 is UITapGestureRecognizer }, true) {
(recognizers[index] as! UIPanGestureRecognizer).requireGestureRecognizerToFail(keyboardDismissTapGesture)
}
Maybe not the most elegant way of doing it, but it works for me when I want to fail the UIPanGestureRecognizer. I haven't tested it with the UITapGestureRecognizer.
EDIT:
if let recognizers = yourTableView.gestureRecognizers, let index = find(recognizers.map { $0 is UIGestureRecognizer }, true) {
(recognizers[index] as! UIGestureRecognizer).requireGestureRecognizerToFail(keyboardDismissTapGesture!)
}

Resources