pajevic
pajevic

Reputation: 4667

Tapping a NSLinkAttributeName link in UITextView not working in iOS 9

I have an UITextView with attributed text which is set up like this:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"This is a message.\nClick here for more info"];
textView.linkTextAttributes = @{NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle)};
NSRange linkRange = [attributedString.string rangeOfString:@"Click here for more info"];
[attributedString addAttribute:NSLinkAttributeName value:@"" range:linkRange];
textView.attributedText = attributedString;
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(infoTapped:)];
[textView addGestureRecognizer:tapRecognizer

Then I catch a tap like this:

- (void)infoTapped:(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];
    NSString *link = attributes[NSLinkAttributeName];

    if (link) {
        // Do stuff
    }
}

In iOS 10 this works fine and I am able to detect the NSLinkAttributeName attribute. However, in iOS 9 the call to [textView closestPositionToPoint:tapLocation] returns nil and I am not able to do anything from there on.

Btw. My textview has both editable and selectable set to NO. I know some say that selctable needs to be set to YES, but I am not sure it's true. First of all, it works fine without selectable in iOS 10. Second, if I do set it to selectable it does work, but only sort of. I do get the tap in iOS 9, but it only works erratically (in both 9 and 10). Sometimes it registers the tap and sometimes it doesn't. Basically, when I see the link highlight like when you click a link in a browser it doesn't register. Furthermore, the text in the text view can now be selected which I do not want.

Upvotes: 1

Views: 3341

Answers (1)

Stas Volskiy
Stas Volskiy

Reputation: 451

Why do you want to select links using tap gesture? UITextView has perfect links recognition feature. I can't answer why your solution doesn't work properly on iOS 9 but I can suggest you to handle links in another way. This will work on iOS 9 as well.

    NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"This is a message.\nClick here for more info" attributes:nil];
NSRange range = [str.string rangeOfString:@"Click here for more info"];
// add a value to link attribute, you'll use it to determine what link is tapped
[str addAttribute:NSLinkAttributeName value:@"ShowInfoLink" range:range];
self.textView.linkTextAttributes = @{NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle)};
self.textView.attributedText = str;
// set textView's delegate
self.textView.delegate = self;

Then implement link related method of UITextViewDelegate:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction
{
    if ([URL.absoluteString isEqualToString:@"ShowInfoLink"]) {
        // Do something
    }
    return NO;
}

To make it works you have to set selectable = YES and check links flag in storyboard to be able detect links.

Upvotes: 6

Related Questions