2
votes

I have a "search" UITextField at the top of my view. Below this, I have a UICollectionView which is populated with the search results as the user types.

When a user is typing into the UITextView, the keyboard is displayed. At first, I wanted to hide the keyboard if the user touched anywhere outside the UITextField. I accomplished this with the following:

func textFieldDidBeginEditing(textField: UITextField) {

    if (textField == self.textFieldSearch) {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "textFieldSearchDidChange:", name: UITextFieldTextDidChangeNotification, object: textField)
    }

    var tapGesture = UITapGestureRecognizer(target: self, action: "dismissKeyboard:")
    self.view.addGestureRecognizer(tapGesture)

}

func dismissKeyboard(gesture: UIGestureRecognizer) {
    self.textFieldSearch.resignFirstResponder()
    self.view.removeGestureRecognizer(gesture)
}

However, if the user taps on a UICollectionViewCell, the dismissKeyboard func runs, and hides the keyboard, but the user has to tap on the cell again to run the func:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

How do I do this all in one step? So if the user touches anywhere outside the UITextField, hide the keyboard...but if the user happens to touch a UICollectionViewCell, run the didSelectItemAtIndexPath function on the first touch as well as hide the keyboard and end editing on the UITextField?

Any help is appreciated! Thanks

5

5 Answers

1
votes

Please try this one

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
        if touch.view == self.textFieldSearch{
            return false;
        }
        else{
            return true;
        }
    }

and add this line in your code

var tapGesture = UITapGestureRecognizer(target: self, action: "dismissKeyboard:")
tapGesture.delegate = self // add gesture delegate here 
    self.view.addGestureRecognizer(tapGesture)
1
votes

You can implement the delegate method of UIGestureRecognizerDelegate

optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
             shouldReceiveTouch touch: UITouch) -> Bool

Above method returns NO for the views on which gesture recognizer should not be called and in your case it should be collection view else for other things return YES.

example implementation-

/**
    Disallow recognition of tap gestures on the collection view.
*/
    func gestureRecognizer(recognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool 
{
        if touch.view == collectionView && recognizer == tapRecognizer     {
            return false
        }
        return true
 }
0
votes

Here's a solution. A little janky but it should do the trick. You might have to tinker with it a little. Also my Swift isn't top notch so excuse any syntax errors.

func dismissKeyboard(gesture: UIGestureRecognizer) {
    let point : CGPoint = gesture.locationInView(self.collectionView)
    let indexPath : NSIndexPath = self.collectionView.indexPathForItemAtPoint(point)

    self.textFieldSearch.resignFirstResponder()
    self.view.removeGestureRecognizer(gesture)

    self.collectionView.selectItemAtIndexPath(indexPath, animated:YES, scrollPosition:UICollectionViewScrollPosition.Top)
}
0
votes

I am providing here a Objective-C code to dismiss keyBoard on any touch performed outside. Kindly write it in Swift for yourself. The problem is you are adding A tap Gesture which is hiding the touch events of your collection cell.

So instead of tap gesture use the Swift-translated code of the following code.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

Dont use your tap gesture. And I think things should get going for you...

EDIT

Some efforts to write the above code in swift for you...

override func touchesBegan(touches: NSSet, withEvent event: UIEvent){

    self.view.endEditing(true)

}
0
votes

This is the code that ended up finally working, with the help of @Sanjay above. I still wanted to hide the keyboard if the user touched on the part of the collectionView that wasn't occupied by cells. I will still have to implement code for hiding the keyboard if a user 'swipes/scrolls/drags' on the UICollectionView instead of taps.

For now:

func gestureRecognizer(recognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {

    for cell:AnyObject in self.collectionView.visibleCells() {
        if (touch.view.isDescendantOfView(cell as UIView)) {
            self.resignAllResponders()
            return false
        }
    }

    return true

}