4

currently I want to let UITextView to have a double tap gesture. It seems UITableView has its own double tap gesture, when we double tapped, some text will be selected. So I want to remove this default double tap gesture to my own gesture recognizer. I tried many methods, and all failed. It seems there's no way to remove the default recognizer of UITextView. I also want to add a transparent view on this UITextView to do double tap event, but this subview will block other gestures on UITextView. Is there some method to add double tap gesture recognizer to UITextView? I really hope there will be a work around.

I am still expecting a work around of iOS5 :)

Charlesjean
  • 566
  • 1
  • 5
  • 15

3 Answers3

13

There are a number of other gesture recognizers attached to a text view. Since you don't seem to need them. You can remove them.

myTextView.gestureRecognizers = nil;

before adding your double tap recognizer. It works.

then you can add

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(mySelector)];
tapRecognizer.numberOfTapsRequired = 2;
tapRecognizer.numberOfTouchesRequired = 1;
[myTextView addGestureRecognizer:tapRecognizer];
Mohammad Rabi
  • 1,404
  • 2
  • 19
  • 39
  • I am under iOS6, I don't if this method work or not before ios6 – Charlesjean Nov 29 '12 at 13:42
  • I know this is an old question, but I came across a different solution myself. Using the above technique will work, if you also set the TextView's editable property to NO and subclass it to set the canBecomeFirstResponder to automatically return NO as well. – Pete.Mertz Apr 04 '13 at 18:33
2

I have the solution on iOS6, we can use UIGestureRecognizerDelegate, and override gestureRecognizerShouldBegin: and gestureRecognizer:shouldReceiveTouch:. In this two method, we can check if the gesture is doubleTapGestureForZooming, if not return NO, or return YES. This works perfect in iOS6, but in iOS5 these two delegate method hasn't been called, so iOS5 may need another workaround. Finally, I get the workaround, we can override the addGestureRecognizer method of UITextView to remove default gesture, wish this will help somebody else.

PS: we really can't remove system gestures of UITextView, we even can't change their property. It seems when event happens, all gestures of UItextview will be added again.

Charlesjean
  • 566
  • 1
  • 5
  • 15
1

I know this question is old, but to keep it current for future searchers, I figured I would add another solution that has worked for me from iOS 7 through 10. It basically brings together the solutions discussed here and here but tweaks them to get the UITextView to recognize the custom double tap.

It does this by subclassing the UITextView and overriding the addGestureRecognizer: method in order to inject our custom callback into the double-tap gesture and configure the single-tap gesture to respect the new double tap hook.

I do this in addGestureRecognizer: because a UITextView constantly deletes and adds gestures depending on its current state and so you constantly have to reset it back up.

This code should be enough to get someone started:

@interface MyCustomTextView ()

/**
 *  we want to keep track of the current single-tap gesture so we can make sure
 *  it waits for a double-tap gesture to fail before firing
 */
@property (weak, nonatomic) UITapGestureRecognizer *singleTap;

/**
 *  we want to keep track of the current double-tap gesture so we can tell a single
 *  tap gesture to ignore this double-tap when the single tap gesture changes
 */
@property (weak, nonatomic) UITapGestureRecognizer *doubleTap;

@end


@implementation MyCustomTextView

/**
 *  this will fire when the text view is double-tapped
 *
 *  @param tgr
 */
- (void)_handleTwoTaps:(UITapGestureRecognizer *)tgr
{
    // ADD CODE HERE
}

/**
 *  the reason why I've overridden this methods is these gestures change quite a bit
 *  depending on the state of the UITextView, (eg, when in focus and out of focus)
 *  and so this provides a reliable way to make sure any new gestures get updated
 *  with custom overrides.
 *
 *  @param gestureRecognizer
 */
- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
    [super addGestureRecognizer:gestureRecognizer];
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        UITapGestureRecognizer *tgr = (UITapGestureRecognizer *)gestureRecognizer;
        if ([tgr numberOfTapsRequired] == 1 && [tgr numberOfTouchesRequired] == 1) {
            self.singleTap = tgr;
            if (self.doubleTap) {
                [tgr requireGestureRecognizerToFail:self.doubleTap];
            }

        } else if ([tgr numberOfTapsRequired] == 2 && [tgr numberOfTouchesRequired] == 1) {
            [tgr addTarget:self action:@selector(_handleTwoTaps:)];
            self.doubleTap = tgr;
            if (self.singleTap) {
                [self.singleTap requireGestureRecognizerToFail:tgr];
            }
        }
    }
}

// NOTE: I'm not sure if this is needed but it's been there for years
// and so I thought I would include it just in case
- (void)removeGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        UITapGestureRecognizer *tgr = (UITapGestureRecognizer *)gestureRecognizer;
        if ([tgr numberOfTapsRequired] == 2 && [tgr numberOfTouchesRequired] == 1) {
            [tgr removeTarget:self action:@selector(_handleTwoTaps:)];
        }
    }
    [super removeGestureRecognizer:gestureRecognizer];
}

@end
Community
  • 1
  • 1
Jaymon
  • 3,962
  • 2
  • 30
  • 30