Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITextView link tap recognition is delayed

In an iOS 7 app, I have a UITextView with a link in it, but tapping the link doesn't fire. It only responds to an awkward "tap and hold". I want it to respond as soon as a user taps on it, like how a UIWebView link tap works. Here is my setup:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."];
    [text addAttribute:NSLinkAttributeName value:@"myurl://tapped" range:NSMakeRange(6, 16)];

    self.textView.attributedText = text;
    self.textView.editable = NO;
    self.textView.delaysContentTouches = NO;
}

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
    if ([[URL scheme] isEqualToString:@"myurl"])
    {
        // Handle tap

        return NO;
    }

    return YES;
}

The Apple Documentation for the shouldInteractWithURL method states: "The text view calls this method if the user taps or long-presses the URL link". The long-press is working, but the tap doesn't seem to work.

Does anyone know how to get this to respond immediately?

like image 230
lehn0058 Avatar asked Mar 13 '14 13:03

lehn0058


3 Answers

If you still want to go with a native UITextView, you can add a tap recognizer to your textview and get the string attributes at the tap location. When you find a link, you can open it immediately.

I wrote a Gist that solves this for iOS 7/8. It's a lightweight extension of UITextView that also forwards -[UITextViewDelegate textView:shouldInteractWithURL:inRange:] and exposes the internal tap gesture recognizer.

https://gist.github.com/benjaminbojko/c92ac19fe4db3302bd28

Here's a quick example:The example below only works on iOS 8. See the gist above for iOS 7 + 8 support.

Add your tap recognizer:

// ...

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedTextView:)];
[myTextView addGestureRecognizer:tapRecognizer];
myTextView.selectable = YES; // otherwise the gesture won't recognize

// ...

And add your callback:

- (void)tappedTextView:(UITapGestureRecognizer *)tapGesture {
    if (tapGesture.state != UIGestureRecognizerStateEnded) {
        return;
    }

    UITextView *textView = (UITextView *)tapGesture.view;
    CGPoint tapLocation = [tapGesture locationInView:textView];
    UITextPosition *textPosition = [textView closestPositionToPoint:tapLocation];
    NSDictionary *attributes = [textView textStylingAtPosition:textPosition inDirection:UITextStorageDirectionForward];

    NSURL *url = attributes[NSLinkAttributeName];

    if (url) {
        [[UIApplication sharedApplication] openURL:url];
    }
}

And swift version:

Tap recognizer:

let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("tappedTextView:"))
myTextView.addGestureRecognizer(tapRecognizer)
myTextView.selectable = true

Callback:

func tappedTextView(tapGesture: UIGestureRecognizer) {

        let textView = tapGesture.view as! UITextView
        let tapLocation = tapGesture.locationInView(textView)
        let textPosition = textView.closestPositionToPoint(tapLocation)
        let attr: NSDictionary = textView.textStylingAtPosition(textPosition, inDirection: UITextStorageDirection.Forward)

        if let url: NSURL = attr[NSLinkAttributeName] as? NSURL {
            UIApplication.sharedApplication().openURL(url)
        }

        }
like image 170
Benjamin Bojko Avatar answered Nov 09 '22 18:11

Benjamin Bojko


Is the UITextView selectable?. Try with:

self.textView.selectable = YES;

Edit:

I'm starting to think that maybe a long-press is the only way to fire it contrary to what apple says. Check this link, maybe it will help.

like image 14
nnarayann Avatar answered Nov 09 '22 18:11

nnarayann


As nnarayann mentioned, CCHLinkTextView avoids the problem of delayed tap recognition. This library implements its own gesture recognizer and is now available in version 1.0.

like image 7
Claus Avatar answered Nov 09 '22 17:11

Claus