While my problems seems easy to solve I cannot do it myself.
Basically I got my CollectionViewController that holds all of my data and I've included within it a search bar which filters items from my collection depending on what the user writes.
When an user taps on any item it leads them to another view and so on.
And when the user taps on the search bar, the keyboard shows up and I'd like to hide it whenever the user decides to tap somewhere else.
While I can do that it turns out that every time I hide the keyboard with the methods I found, it also prevents the user from going further into my application, in fact it's not longer possible to go to another view after tapping on them.
Here's what I did :
My CollectionViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
// Setup search bar/collection view
self.collectionView?.dataSource = self
searchBar.delegate = self
searchBar.sizeToFit()
searchBar.placeholder = "Search"
navigationItem.titleView = searchBar
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
searchBar.resignFirstResponder()
}
I also tried many things found here without success. Somehow even if I've included the UIGestureRecognizerDelegate in my file some delegate listed there aren't triggered when I tap somewhere. For example the delegate gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool doesnt work.
I can see the logic right here, but it's just impossible to find any fix that doesn't break the collectionview.
Any help is appreciated, thank you.
Please use below solution for both Objective-c & Swift, I hope it will work for you dear
Swift
create variable let tap = UITapGestureRecognizer() and in viewDidLoad method write below code.
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}
And paste below code for further implementation of methods:
func keyboardWillShow(notification: NSNotification) {
tap = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
}
func keyboardWillHide(notification: NSNotification) {
view.removeGestureRecognizer(tap)
}
(Objective-c) First of all create UITapGestureRecognizer *tap variable and in viewDidLoad method paste below code.
//Notifications for keyBoardShow and keyBoradHide
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
And paste below code:
- (void)keyboardWillShow:(NSNotification *)notif {
//Add tap gesture here
tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
}
- (void)keyboardWillHide:(NSNotification *)notif {
//Remove tap gesture
[self.view removeGestureRecognizer:tap];
}
-(void)dismissKeyboard {
[yourSearchBar resignFirstResponder];
}
#CroiSciento dear check this solution.
check this out
override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
searchBar.resignFirstResponder()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
Related
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.
I have ViewController with UIGestureRecognizer implemented this way:
// Extension for GestureRecognizer
extension UIViewController {
func addGestureRecognizer() {
let singleTap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
singleTap.cancelsTouchesInView = false
singleTap.numberOfTapsRequired = 1
self.view.addGestureRecognizer(singleTap)
}
#objc func handleTap(_ recognizer: UITapGestureRecognizer) {
self.view.endEditing(false)
}
}
As you can see, cancelsTouchesInView is set to false by default. It works fine with main view with searchBar and textFields. Keyboard is being dismissed and touches are translated to view's objects - buttons and so on.
But I have added subview that works like AlertView with several UITextFields and UIButtons. And here is a problem. When subview is presented and I'm tapping on any button of this subview - gestureRecognizer reacts and keyboard disappears. But nothing else happens. So I have to tap the second time on the button to make it pressed.
I have tried to change target of UITapGestureRecognizer from self to self.mySubViewName, like this:
func addGestureRecognizer() {
let singleTap = UITapGestureRecognizer(target: self.addingItemView, action: #selector(self.handleTap(_:)))
singleTap.cancelsTouchesInView = false
singleTap.numberOfTapsRequired = 1
self.view.addGestureRecognizer(singleTap)
}
#objc func handleTap(_ recognizer: UITapGestureRecognizer) {
self.view.endEditing(false)
}
This way GestureRecognizer started to work with subview buttons properly, but is not able to work with main view. I started getting "Unrecognized selector was sent" error when trying to dismiss keyboard for searchbar for example. I have tried to implement separate function addGestureRecognizerForSubView, but still getting "Unrecognized selector was sent..." error.
Also tried to add this:
extension MenuTableViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == self.addingItemView
}
}
but nothing changes.
I've checked a lot of answers here, but was not able to find my case. Can anybody advise? I can share my ViewController class, but it's too heavy and looks ugly with programmatically added subview :)
Add a subview behind the alert and add the gesture to it not to self.view
let singleTap = UITapGestureRecognizer(target: self.otherView, action: #selector(self.handleTap(_:)))
singleTap.cancelsTouchesInView = false
singleTap.numberOfTapsRequired = 1
self.otherView.addGestureRecognizer(singleTap)
Edit: your suggest to add it to a subview is right
let singleTap = UITapGestureRecognizer(target: self.addingItemView, action: #selector(self.handleTap(_:)))
singleTap.cancelsTouchesInView = false
singleTap.numberOfTapsRequired = 1
self.view.addGestureRecognizer(singleTap)
But you still add the gesture to self.view here
self.view.addGestureRecognizer(singleTap)
change to
self.addingItemView.addGestureRecognizer(singleTap)
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().
How can I add a UITapGestureRecognizer to a UITextView but still have the touches getting through to the UITextView as normal?
Currently as soon as I add a custom gesture to my textView it blocks the tap for UITextView default actions like positioning the cursor.
var tapTerm:UITapGestureRecognizer = UITapGestureRecognizer()
override func viewDidLoad() {
tapTerm = UITapGestureRecognizer(target: self, action: "tapTextView:")
textView.addGestureRecognizer(tapTerm)
}
func tapTextView(sender:UITapGestureRecognizer) {
println("tapped term – but blocking the tap for textView :-/")
…
}
How can I process taps but keep any textView behaviour like cursor positioning as is?
To do that make your view controller adopt to UIGestureRecognizerDelegate and override should recognize simultaneously with gesture recognizer method like:
override func viewDidLoad() {
tapTerm = UITapGestureRecognizer(target: self, action: "tapTextView:")
tapTerm.delegate = self
textView.addGestureRecognizer(tapTerm)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
In case anyone came here looking for #Zell B.'s answer in Objective C, here's the code:
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(textViewTapped:)];
tap.delegate = self;
tap.numberOfTapsRequired = 1;
[self.textView addGestureRecognizer:tap];
}
- (void)textViewTapped:(UITapGestureRecognizer *)tap {
//DO SOMTHING
}
#pragma mark - Gesture recognizer delegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
PS: Don't forget < UIGestureRecognizerDelegate >
Swift 4.2
The following steps allows me to escape a full-screen UITextView with a tap, whilst allowing to scroll the contents of the UITextView:
Disconnected the UIGestureRecognizer from the UITableView.
Made a CustomTextView: UITextView.
Added a 'sender' var to the particular UIViewController with the CustomTextView.
Trap for 'Touches Ended...'
Call for an excape function within the sender UIViewController.
class CustomTextView: UITextView {
var sender: DocViewController?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let controller = sender {
controller.handleSwipeGesture()
}
}
}
I can either scroll the contents of the UITextView or merely tap to exit.
The 'sender' is set from the hosting UIViewController at creation.
Somehow I could not assign a delegate inside UIView so I came up with a button solution.
I insert a button that completely covers the textView and when tapped on textViewButton I do resign the button so textView shows.
#IBAction func textViewTapped(_ sender: UIButton) {
self.placeholderLabel.isHidden = true
self.textViewButton.resignFirstResponder()
}
today I tried to run my code on my iPod (iOS 6.1.3) and I found something interesting here...
first, when I tap on textfield the keyboard shows up but it won't hide when I tap somewhere else outside textfield.
so I decided to Googling and found this solution :
_fieldEmail.delegate = self;
_fieldEmail.returnKeyType = UIReturnKeyDone;
_fieldPassword.delegate = self;
_fieldPassword.returnKeyType = UIReturnKeyDone;
_fieldRegisterName.delegate = self;
_fieldRegisterName.returnKeyType = UIReturnKeyDone;
_fieldRegisterEmail.delegate = self;
_fieldRegisterEmail.returnKeyType = UIReturnKeyDone;
_fieldRegisterPassword.delegate = self;
_fieldRegisterPassword.returnKeyType = UIReturnKeyDone;
it works... it gives a 'DONE' button on the bottom of keyboard and now the keyboard can be hidden by pressing it.
but I have 2 problems here :
the keyboard only hide when 'DONE' button is tapped. not by tapping other area outside text field. I don't know if this normal on iOS world, but usually I see lot of apps don't act like this.
is there any way to loop this process so I don't have manually add that delegate one by one of all textfield that I have? how to do that?
that's all I need to know
The below code will work on all the components in the UIView for all the UITextField
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UIView * txt in self.view.subviews){
if ([txt isKindOfClass:[UITextField class]] && [txt isFirstResponder]) {
[txt resignFirstResponder];
}
}
}
OR
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
Simply add an UITapGestureRecogniser to your view that will lead to calling resignFirstResponder
In viewDidLoad :
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(hideKeyBoard)];
[self.view addGestureRecognizer:tapGesture];
And then :
-(void)hideKeyBoard {
[yourTextField resignFirstResponder];
}
2.You could subclass UITextField but unless you have 1000 textFields it is ok to do like you currently do.
This is regards to Swift programming for Xcode 6.0.1
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleSingleTap:")
tapRecognizer.numberOfTapsRequired = 1
self.view.addGestureRecognizer(tapRecognizer)
}
func handleSingleTap(recognizer: UITapGestureRecognizer) {
self.view.endEditing(true)
}
Use Either
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleTap];
and code of method
-(void)handleSingleTap:(UITapGestureRecognizer *)sender{
[self.TextFiledName resignFirstResponder];
}
OR _ And The best Other option is
Just add
[self.view endEditing:YES];
And key board will hide when you tapped anywhere from view:)
Dismissing the keyboard
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
[super touchesBegan:touches withEvent:event];
}
Simple,
Use IQKeyboardManager and put this line of code in AppDelegate.m
[[IQKeyboardManager sharedManager] setShouldResignOnTouchOutside:YES];
What I usually do is call
[field resignFirstResponder];
from an invisible button over the view. I'm sure theres a nicer way to do it. It's been a while since I've done this in an app.
Here's how I do it:
In the myView's .h file:
#property (strong) UITextField * savedTextField;
In the myView's .m file:
#implementation myView
#synthesize savedTextField;
In the myView's init routine:
[self setSavedTextField: nil];
In the myView's textField delegate area I save the id of whichever textField is currently activating:
- (BOOL) textFieldShouldBeginEditing: (UITextField *) textField
{
[self setSavedTextField: textField];
.
.
.
return( YES );
}
And in the myView's routine that routes all the traffic for the other controls when they are accessed, I have code that looks to see if a textField was active and, if one was, it calls on it to resign its FirstResponder status and then drops a nil into the savedTextField property:
- (void) handleCtrlEvents: (UIControl *) aCtrl
{
if ( [self savedTextField] != nil )
{
[[self savedTextField] resignFirstResponder];
[self setSavedTextField: nil];
}
.
.
.
}
This works cleanly for me.
I ran into the exact same problem. Usually what you want is, that wherever you click inside your App (which is displayed in your main / current UIView) but not on the keyboard to close it. After searching the web for a smart solution and testing several, I think it is the best to extend/subclass/implement the UIGestureRecognizerDelegate
Since many controls such as UITableView etc. can respond to gestures (select, scrolling etc.) and if you simply add a UITapGestureRecognizer to the whole (main-)ViewController's view to close the keyboard, the user experience is not the best, since the user needs to tap twice if he didn't intend to close the keyboard but e.g. select a row from a UITableView inside the App's current "main" View.
Since I am quite new to the whole iOS and swift thing and swift code examples are rare, here's my full keyboard control snipped:
class ViewController: UIViewController, UIGestureRecognizerDelegate {
override func viewDidLoad(){
self.initializeCloseKeyboardTap()
}
func initializeCloseKeyboardTap() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboardOpen:", name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboardClose:", name: UIKeyboardDidHideNotification, object: nil)
let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleOnTapAnywhereButKeyboard:")
tapRecognizer.delegate = self //delegate event notifications to this class
self.view.addGestureRecognizer(tapRecognizer)
}
func onKeyboardClose(notification: NSNotification) {
println("keyboardClosed")
}
func onKeyboardOpen(notification: NSNotification) {
println("keyboardOpen")
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
self.view.endEditing(true)
return false
}
you can nest it inside the ViewController and call initiallizeCloseKeyboardTa() in viewDidLoad implementation... It also implements a norfication observer to receive events as soon as the keyboard (finished to be) opened or closed via NSNotificationCenter UIKeyboardDidShowNotification and UIKeyboardDidHideNotification
Hope that save's other people some time :-)
|*| Dismissing the UITextField’s Keyboard : override the method touchesBegan:withEvent: for the ViewController
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
view.endEditing(true)
super.touchesBegan(touches, withEvent: event)
}
|OR|
override func viewDidLoad()
{
super.viewDidLoad()
// For tapping outside text box
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DismisKeyPadFnc)))
}
// For tapping outside text box
func DismisKeyPadFnc()
{
view.endEditing(true)
}
|*| Dismissing the UITextField’s Keyboard on induvidual textbox :
class NamVcc: UIViewController, UITextFieldDelegate
{
#IBOutlet var NamTxtBoxVid: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
// For hitting return key
NamTxtBoxVid.delegate = self
// For tapping outside text box
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DismisKeyPadFnc)))
}
/* For hitting return key */
func textFieldShouldReturn(NamTxtBoxPsgVid: UITextField) -> Bool
{
NamTxtBoxPsgVid.resignFirstResponder()
return true
}
/* For tapping outside text box */
func DismisKeyPadFnc()
{
view.endEditing(true)
}
}
|*| Implementing Next button Click :
1) You will be needing to set the tags in the incremental sequence of the textfields in xib/Storyboard or in code.
2) Set the delegate for each of the textfields.
3) Then paste the following code in your view controller to have the desired effect:
func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
{
let NxtTxtBoxTagVal : Int = TxtBoxPsgVar.tag + 1
let NxtTxtBoxVal: UIResponder? = TxtBoxPsgVar.superview?.superview?.viewWithTag(NxtTxtBoxTagVal)
if let TxtBoxVal = NxtTxtBoxVal
{
// Found next responder, so set it.
TxtBoxVal.becomeFirstResponder()
}
else
{
// Not found, so remove keyboard.
TxtBoxPsgVar.resignFirstResponder()
}
return true
}
I prefer IQKeyboardManager. You can simply handle keyboard in any state. To active IQKeyboard just add one line in AppDelegate and to dismiss keyboard on outside touch add code as below,
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
IQKeyboardManager.shared.enable = true
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
return true
}
I think
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
is convenient but not the best solution.
and the TapGestureRecongnizer is better but hard to use,you have to set delegates and add and remove the Recongnizer.
So I wrote a simple subclass which can be easily used:
class TapHideTextField: UITextField {
override func awakeFromNib() {
super.awakeFromNib()
tapGr = UITapGestureRecognizer(target: self, action:"tap")
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBeginEditing", name:UITextFieldTextDidBeginEditingNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didEndEditing", name:UITextFieldTextDidEndEditingNotification, object: nil)
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self)
}
var tapGr:UITapGestureRecognizer!
func tap(){
self.endEditing(true)
}
func didBeginEditing(){
self.superview!.addGestureRecognizer(tapGr)
}
func didEndEditing(){
self.superview!.removeGestureRecognizer(tapGr)
}
}
you should concern about the superview and the cancelTouchesInView property.
or in GitHub:https://github.com/lilidan/TapHideText/blob/master/TapHideTextField.swift
If you're using scroll view (or table view) controller, add these lines there:
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
view.endEditing(true)
}
-(void) textFieldDidBeginEditing: (UITextField *) textField{
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(DismissKeyboard:)]];
}
-(void) DismissKeyboard:(UITapGestureRecognizer *) sender{
[self.view endEditing:YES];
[self.view removeGestureRecognizer:sender];
}