Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow cursor selection anywhere in UITextView

Tags:

ios

uitextview

I have a single UITextView, which lets you write multiple lines of text.

How can I let users select letters in between words without a long press?

Currently, when using the touchscreen to select characters between a word, the cursor either goes the start or end of the word:

Example: clicking on 'c' moves cursor to end of word

cursor at end

Example: clicking on 'a' moves cursor to start of word

cursor at start

Desired cursor behavior: Selection anywhere in text enter image description here

The feature of allowing text selection anywhere (without the long press + magnifying glass) is found in many code editor apps for iOS, such as Coda and Pythonista.

like image 481
user2560886 Avatar asked Oct 17 '22 20:10

user2560886


1 Answers

This is not a difficult challenge to achieve.

I will preface that the issue with this approach is consistency. Remember that your users are using their fingers, rather than stilii. A finger has a large surface area, and hitting a precise pixel zone is quite difficult, especially with small text. I would suggesting playing not in the simulator, where you have a precise pointing device, but on a device.

The first challenge is to disable the default tap behavior or UITextView. This is not a difficult task - you can either "attack" the problem at the touchesBegan:withEvent: level, where you would have to understand what these touches are (single tap vs. pan vs. long press), or at the gesture recognizer level, where you'd disable the private gesture recognizers of the text view which specifically handle cursor movement in case of tap (vs the other touch types). I've done the latter for various projects, and it is possible. You could also try the approach without disabling the default behavior, but then the cursor may flicker. Test and decide.

Now to achieve what you need. Obtain the point of touch somehow (either using UIResponder API or gesture recognizer). Remember, the text view is a scroll view which includes a large subview where the content is drawn into. You have to convert this touch point, from the text view coordinate system, to the internal view's coordinate system using the convertPoint: API. Once you have that, you can use the text view's layout manager to obtain the character index at the point of touch:

NSUInteger chIdx = [self characterIndexForPoint:touchPoint inTextContainer:self.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];

You can use this index to set the cursor of the text view using the selectedRange property.

like image 172
Léo Natan Avatar answered Oct 21 '22 06:10

Léo Natan