I am using this code to dismiss keyboard when user click's outside the TextField
override func viewDidLoad() {
...
let tapGesture = UITapGestureRecognizer(target: self, action: "tap:")
view.addGestureRecognizer(tapGesture)
...
}
func tap(gesture: UITapGestureRecognizer) {
txtName.resignFirstResponder()
}
It is working when the user click's anywhere outside the textfield but the datepicker. When he put's a name and then click on the DatePicker (just click, not roll) the tap is not recognized.
What should I do to make it work?
It's possible the gesture recogniser on the DatePicker is interfering with yours. See if modifying this function helps your case.
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true //Obviously think about the logic of what to return in various cases
}
Related
I have added GestureRecognizer for hide keyboard when user click to anywhere in view without textview. Its working well but CollectionView Cells need two tap for work, when I delete GestureRecognizer its working well but I need both of them. I have searched this in couple hours and tried so many solutions but anything is not worked.
GestureRecognizer for hide keyboard when user click to anywhere in view without textview;
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tapRecognizer.cancelsTouchesInView = false
view.addGestureRecognizer(tapRecognizer)
#objc func handleTap() {
textBody.endEditing(true)
}
You can try this method:
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true) // or textBody.endEditing(true)
}
To recognize both gestures simultaneously use below code by removing cancelsTouchesInView line. You may need to add another tap gesture for your collectionView according to your need. Or use scrollViewDidScroll event of collectionView to hide the keyboard.
//tapRecognizer.cancelsTouchesInView = false
tapRecognizer.delegate = self
view.addGestureRecognizer(tapRecognizer)
extension MyViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
I have this Setup in my Storyboard.
In my first ViewController Scene I have a MapView from MapBox. In there I have put a TextField (AddressTextField). On that TextField when touching the view, i'm running self.addressTextField.resignFirstResponder(), but after that neither the mapview, nor any other element in there or in the Embedded Segues react on a touch or click. Probably this is because I didn't completely understand the system of the First Responder. I'm thankful for every help.
Edit 1:
I think I know what's going on now, but I don't know how to fix it. When I add the Gesture Recognizer to the View (or to the mapView, that doesn't matter), the other UIViews and the MapView do not recognize my Tap-Gestures anymore. When I am not adding the Recognizer everything works fine. It seems as if the Gesture Recognizer is recognizing every tap I make on either the UIViews or the MapView and therefore other gestures are not recognized.
Edit 2:
I just added a print() to dismissKeyboard(). As soon as any Touch Event gets recognized on the MapView or the other UIViews, dismissKeyboard() gets called. So I think my thought of Edit 1 was correct. Does anyone know how I can solve this, so that it's not only dismissKeyboard() that gets called ?
Some Code:
func dismissKeyboard(){
self.addressTextField.resignFirstResponder()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
dismissKeyboard()
return true
}
//Class (only partially)
class ViewController: UIViewController, MGLMapViewDelegate, CLLocationManagerDelegate, UITextFieldDelegate {
override func viewDidLoad(){
mapView.delegate = self
addressTextField.delegate = self
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
self.mapView.addGestureRecognizer(tap)
}
}
Others are just #IBActions linked to the Buttons, or other elements.
try this:
func dismissKeyboard(){
view.endEditing(true)
}
hope it helps!
After I knew the real issue I was able to solve the problem. I declared a var keyboardEnabled. Then I added these lines to my class.
class ViewController: UIViewController, UIGestureRecognizerDelegate {
var keyboardEnabled = false
override func viewDidLoad(){
super.viewDidLoad()
//Looks for single tap
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
self.mapView.addGestureRecognizer(tap)
}
/* Setting keyboardEnabled */
//Editing Target did end
#IBAction func editingTargetDidEnd(_ sender: Any) {
keyboardEnabled = false
}
//Editing TextField Started
#IBAction func editingAdressBegin(_ sender: Any) {
keyboardEnabled = true
}
//Call this function when the tap is recognized.
func dismissKeyboard() {
self.mapView.endEditing(true)
keyboardEnabled = false
}
//Implementing the delegate method, so that I can add a statement
//decide when the gesture should be recognized or not
//Delegate Method of UITapGestureRecognizer
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return keyboardEnabled
}
}
With this solution keyboardEnabled takes care of deciding wether my UIGestureRecognizer should react or not. If the Recognizer doesn't react, the Gesture is simply passed on to the UIViews or other Elements that are in my MapView.
Thanks for all your answers!
I don't know how exactly to achieve the following in Swift:
I am displaying a modal form sheet popup in my iPad app. In order to dismiss this view I have added a button that dismisses it. But what I really want is for it to dismiss when you click outside of the view. Almost the same behaviour as the popover. I have tried achieving this by adding tap gestures, making it a popover, any of the presentation styles, nothing works.
Has someone maybe done this so that you can point me in the right direction?
I had to display some screens like a popup in my app, so I've made a
base class that looks like this:
class MyBasePopUp: UIViewController, UIGestureRecognizerDelegate {
var tap: UITapGestureRecognizer!
override func viewDidAppear(_ animated: Bool) {
tap = UITapGestureRecognizer(target: self, action: #selector(onTap(sender:)))
tap.numberOfTapsRequired = 1
tap.numberOfTouchesRequired = 1
tap.cancelsTouchesInView = false
tap.delegate = self
self.view.window?.addGestureRecognizer(tap)
}
internal func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
internal func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
let location = touch.location(in: self.view)
if self.view.point(inside: location, with: nil) {
return false
}
else {
return true
}
}
#objc private func onTap(sender: UITapGestureRecognizer) {
self.view.window?.removeGestureRecognizer(sender)
self.dismiss(animated: true, completion: nil)
}
This is just to dismiss the popup, be careful if you have multiple gestures.
The google login button provided by google (GIDSignInButton), is not working in normal press but in long press. Otherwise evrything is normal.
Any idea guys?
That was due to a tap recognizer I had in the same viewcontroller. Issue got solved.
Google sign in default button not works in single tap, it works after 1
long press because of the Tap Gesture included in same
viewcontroller...
So the Solution is Handle touch event in sameViewcontroller:
override func viewDidLoad() {
super.viewDidLoad()
let touchRecognizer = UITapGestureRecognizer(target: self, action:
#selector(onBaseTapOnly))
touchRecognizer.numberOfTouchesRequired = 1
touchRecognizer.delegate = self
self.view.addGestureRecognizer(touchRecognizer)
}
func onBaseTapOnly(sender: UITapGestureRecognizer) {
if sender.state == .ended {
//react to tap
self.view.endEditing(true)
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
I have a UIWebView in which I've implemented a single tap gesture recognizer. I don't have any recognizer for long hold, though my problem is in making a selection. Issues:
Select some text in a UIWebView, select copy from contextual menu. Menu should disappear.
Long hold to make a text selection, single tap gesture is also getting called.
If text is selected, a single tap elsewhere should remove the selection like in Safari.
…
func createGestureRecognizer() {
// single tap
let singleTapGesture = UITapGestureRecognizer(target: self, action: "handleSingleTap:")
singleTapGesture.numberOfTapsRequired = 1
singleTapGesture.delegate = self
singleTapGesture.cancelsTouchesInView = false
webView.addGestureRecognizer(singleTapGesture)
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view.isDescendantOfView(self.webView) {
return true
}
return true
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if otherGestureRecognizer.isKindOfClass(UITapGestureRecognizer) {
otherGestureRecognizer.requireGestureRecognizerToFail(gestureRecognizer)
// println("added failure requirement to: \(otherGestureRecognizer)")
}
return true
}
func handleSingleTap(tap: UITapGestureRecognizer) {
…
}
EDIT: It is sort of working. Problem: Making an initial text selection requires a longer hold than normal. A normal long hold that would normally make a selection calls my single tap recognizer without selecting any text.
func handleSingleTap(tap: UITapGestureRecognizer) {
let selection = webView.stringByEvaluatingJavaScriptFromString("window.getSelection().toString()")!
if selection == "" {
// do stuff
} else {
webView.userInteractionEnabled = false
webView.userInteractionEnabled = true
webView.stringByEvaluatingJavaScriptFromString("window.getSelection().removeAllRanges()")
}