asaf am
asaf am

Reputation: 1395

UITextView taps on end of line should not return word in next line

I am trying to segue upon taps on specific words in a UITextView (not editable) - imagine hashtags or mentions in Instagram or Twitter mobile apps.

This post helped me understand how to identify taps on specific words inside a UITextView:

- (void)viewDidLoad
{
    [super viewDidLoad];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self     action:@selector(printWordSelected:)];
    [self.textView addGestureRecognizer:tap];
}

- (IBAction)printWordSelected:(id)sender
{
    NSLog(@"Clicked");

    CGPoint pos = [sender locationInView:self.textView];
    NSLog(@"Tap Gesture Coordinates: %.2f %.2f", pos.x, pos.y);

    //get location in text from textposition at point
    UITextPosition *tapPos = [self.textView closestPositionToPoint:pos];

    //fetch the word at this position (or nil, if not available)
    UITextRange * wr = [self.textView.tokenizer rangeEnclosingPosition:tapPos
                                                       withGranularity:UITextGranularityWord
                                                           inDirection:UITextLayoutDirectionRight];

    NSLog(@"WORD: %@", [self.textView textInRange:wr]);
} 

Unfortunately, this approach is not bullet proof and report taps on white space in the end of the line as taps on words in the beginning of the next line.

Obviously this is a result of word wrapping in UITextView that sometimes moves words to the beginning of the next line.

  1. Is there a way to fix it and not report these clicks on the end of the line as clicks on the wrapping words?
  2. Is there a better approach to segue upon user taps on specific words inside UITextView?

Upvotes: 2

Views: 941

Answers (1)

Marcus Adams
Marcus Adams

Reputation: 53830

A simple solution is to only return the word if it's the same in both directions (left and right). There is one limitation with this approach, however. You won't be able to select single character words.

- (IBAction)printWordSelected:(id)sender
{
    CGPoint pos = [sender locationInView:self.textView];

    //get location in text from textposition at point
    UITextPosition *tapPos = [self.textView closestPositionToPoint:pos];

    //fetch the word at this position (or nil, if not available)
    UITextRange * wr = [self.textView.tokenizer rangeEnclosingPosition:tapPos
                                                       withGranularity:UITextGranularityWord
                                                           inDirection:UITextLayoutDirectionRight];

    //fetch the word at this position (or nil, if not available)
    UITextRange * wl = [self.textView.tokenizer rangeEnclosingPosition:tapPos
                                                       withGranularity:UITextGranularityWord
                                                           inDirection:UITextLayoutDirectionLeft];


    if ([wr isEqual:wl]) {

        NSLog(@"WORD: %@", [self.textView textInRange:wr]);
    }
} 

Upvotes: 2

Related Questions