user3607973 user3607973 - 3 months ago 12
Objective-C Question

Get currently typed word in a UITextView

I want to get the currently typed word in a

UITextView
. A way to get a completely typed word can be found here UITEXTVIEW: Get the recent word typed in uitextview, however, I want to get the word while it is being typed (no matter where it is typed, beginning, middle, end of
UITextView
).

I guess what defines a word being typed is a whitespace character followed by alphanumeric characters, or if the current location (somehow to figure out with
range.location
) is the beginning of the
UITextView
then whatever follows up should be considered as word as well. A word is finished being typed when another whitespace character follows.

I tried with:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text`


but I have a problem finding the correct range.

In short again: I need to find the substring in a
UITextView
, where substring is the currently typed word.

EDIT: Because the question came up. I'm using
NSLayoutManager
and bind a
NSTextContainer
to it, which then is passed as layoutManager to a
NSTextStorage
.

EDIT2: The main problem with
(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
is that the
range.location
is not the same as the indicator is, but always 1 less. If the cursor is at position 1, after typing one letter,
range.location
would return 0. Any way around this? In addition the
text
attribute of
UITextView
seems to be off by 1 as well. When the text is
foobar
and I output the
UITextView.text
then I get
fooba
instead. Therefore
range.location+1
returns the exception
Range {0, 1} out of bounds; string length 0'


EDIT3:
Maybe it is easier to get my wanted result with the
NSTextStorage
instead of
UITextView
?

Answer

The UITextView delegate method : -textView:textView shouldChangeTextInRange:range replacementText:text what actaully does is that it asks whether the specified text should be replaced in the text view in the specified range of textView.text .

This method will be invoked each time when we type a charactor before updating that to the text view. That is why you are getting the range.location as 0, when you type the very first character in the textView.

Only if the return of this method is true, the textView is getting updated with what we have typed in the textView.

This is the definition of the parameters of the -textView:textView shouldChangeTextInRange:range replacementText:text method as provided by apple:

range :- The current selection range. If the length of the range is 0, range reflects the current insertion point. If the user presses the Delete key, the length of the range is 1 and an empty string object replaces that single character.
text :- The text to insert.

So this is what the explanation for the method and your requirement can meet like as follows:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
        //Un-commend this check below :If you want to detect the word only while new line or white space charactor input 
        //if ([text isEqualToString:@" "] || [text isEqualToString:@"\n"])
        //{
            // Getting the textView text upto the current editing location
            NSString * stringToRange = [textView.text substringWithRange:NSMakeRange(0,range.location)];

            // Appending the currently typed charactor
            stringToRange = [stringToRange stringByAppendingString:text];

            // Processing the last typed word 
            NSArray *wordArray       = [stringToRange componentsSeparatedByString:@" "];
            NSString * wordTyped     = [wordArray lastObject];

            // wordTyped will give you the last typed object
            NSLog(@"\nWordTyped :  %@",wordTyped);
        //}
        return YES;
}
Comments