Detecting tapped character. UITextView characterRangeAtPoint always returns nil

Posted on

Detecting tapped character. UITextView characterRangeAtPoint always returns nil

I’m trying to determine, which particular character in UITextView has been tapped. I tried to use characterRangeAtPoint: method. But it always returns nil, wherever in the UITextView I tap.
I even wrote and run the following piece of code:

for (int x = 0; x<1000; x++) {
    pos.x = x;
    for (int y = 0; y<1000; y++) {
        pos.y = y;
        UITextRange * range = [textView characterRangeAtPoint:pos];
        if (range!=nil) {
            NSLog(@"x: %f, y: %f", pos.x, pos.y);

Well, it never reaches the NSLog string.
What am I doing wrong?

Solution :

This is an iOS 7 bug. characterRangeAtPoint: always returns nil, unless some text has been selected at least once beforehand.

As a workaround, you could call setSelectedRange: or setSelectedTextRange: beforehand, but then the textView would highlight your selection. I came up with the following solution:

[textView select:textView];
[textView setSelectedTextRange:nil];

After you call these two methods, characterRangeAtPoint: will start working as expected.

Note that you just need to call this once after textView has been initialized.

EDIT: my answer was edited from “unless some text has been selected beforehand” to “unless some text is currently selected”. This is wrong: text doesn’t need to be currently selected, it just has to be selected once. All subsequent calls to setSelectedRange: will then be successful, as stated in my note. Edited back for further clarity.

Your UITextView must be selectable. In storyboard, check the “Selectable” checkbox.

In code,

textView.selectable = YES;

This is also required for the -closestPositionToPoint: method on UITextView.

Use shouldChangeCharactersInRange method instead of characterRangeAtPoint.

And use your If condition inplace of loop statement.

Is your TextView user-editable?
If YES, then try the texViewDidChangeSelection method. It is invoked every time the caret(cursor) is moved in a textView. Then get the cursor position by textView.selectedRange.location to point to the index, of the caret.

My assumption here is that you want the location of the character with respect to the number of character, and not co-ordinates in 2D.

Leave a Reply

Your email address will not be published. Required fields are marked *