Creating a UIView that captures taps, but is transparent to all other gestures
Asked Answered
I

3

9

I want to achieve the following.

Scenario: The iOS keyboard is on-screen while the user is typing into a particular text field. The user can tap anywhere outside of the keyboard and text field to dismiss the keyboard (without activating any buttons which are visible). Also, the user can drag outside of the keyboard and observe the normal drag behavior on some arrangement of scrollable views.

Conceptually, I’m placing a “cover” UIView over most of the screen which behaves such that:

  1. If the user taps on the cover, then I capture that tap (so that I can, e.g., dismiss the keyboard). This is easy to achieve by intercepting touch events in a UIView subclass or using a tap gesture recognizer.

  2. If the user drags on the cover, then the cover ignores or forwards these touches; these are received by the layers underneath just as they would have been without a cover.

So: the user should be able to scroll content underneath the cover, but not tap content underneath the cover. A tap “outside” of the keyboard and text field should dismiss the keyboard (and cover), but should not activate anything.

How can I achieve this?

Ial answered 16/11, 2012 at 8:28 Comment(1)
You have to consider implementing the touches delegate method and pass on the touches to the views which are behind it for swiping. - (void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*)event{ [otherView touchesBegan:touches withEvent:event]; } Another way is to implement, UIPanGestureRecognizer and set cancelsTouchesInView = YES as UIPanGestureRecognizer *gr = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan)]; [gr setCancelsTouchesInView:YES]; [myButton addGestureRecognizer:gr]; [gr release];Rostov
E
2

Add the tap gesture the usual way:

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
[self.view addGestureRecognizer:tapGesture];

But what you may be looking for is this :

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {    
        return YES;
    }

Documentation says : This method is called when recognition of a gesture by either gestureRecognizer or otherGestureRecognizer would block the other gesture recognizer from recognizing its gesture. (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIGestureRecognizerDelegate_Protocol/index.html#//apple_ref/occ/intf/UIGestureRecognizerDelegate)

This way, you may be sure it's totally transparent, and also that nothing will prevent your recognizer from being called.

Emmer answered 16/11, 2012 at 8:45 Comment(0)
E
1

A custom view which forwards all touches it receives:

class CustomView: UIView {

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

        var hitView = super.hitTest(point, withEvent: event)

        if hitView == self {
            return nil
        }

        return hitView
    }    
}

From there you can go different ways to just make use of tap gestures. Either observe the UIEvent for its touches, or use a gesture recognizer.

Edema answered 27/8, 2015 at 17:15 Comment(0)
J
0

1: Add a tap gesture recognizer to the view:

    //Adding tap gesture
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
    tapGesture.numberOfTapsRequired = 1;
    [self.view addGestureRecognizer:tapGesture];

2: In handleTapGesture you resignFirstResponder of the keyboard

- (void)handleTapGesture:(UITapGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateRecognized) {
       //Resign first responder for keyboard here
    }
}

Elaborated a bit on the answer above. UIGestureRecognizerStateRecognized makes sure it's single tab events that gets recognized.

Is this the functionality you where after?

January answered 16/11, 2012 at 8:32 Comment(2)
His question is "if the user drags on the cover, then the cover ignores all touches; these are received by the layers underneath just as they would have been without a cover.". He has already figured out how to detect touch.Rostov
If the UIView is able to recognize taps, then its .userInteractionEnabled must be YES and it therefore eats all touch events, preventing drags from being recognized by whatever is underneath.Ial

© 2022 - 2024 — McMap. All rights reserved.