Reputation: 6458
I'm having the following problem, and am not sure if this is an iOS bug, or I'm misunderstanding UITextViewDelegate callbacks. I'm able to reproduce this behavior on my device (iPad retina) and on the simulator only if I use the software keyboard (i.e. use my mouse to click the on-screen keyboard).
Consider the following contrived example project (Updated 1/9/14): https://www.dropbox.com/s/1q3vqfnsmmbhnuj/AutocorrectBug.zip
It's a simple UITextView, with a view controller set as its delegate, with the following delegate method:
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([text isEqualToString:@" "]
&& range.length == 0
&& (range.location == 0
|| [[textView.text substringWithRange:NSMakeRange(range.location-1, 1)] isEqualToString:@"\n"])) {
textView.backgroundColor = [UIColor yellowColor];
return NO;
}
return YES;
}
My intention with this code is that when the user types a space (edit: and that space is the first character on the line), the space is ignored and instead some other functionality happens, in this case the UITextView turns yellow.
Now consider these steps:
Expected: A yellow background and text reading:
Apple
Apple
Observed: A yellow background and text reading (due to an autocorrection):
Apple
Apple
It appears the autocorrection logic is ignoring the result of textView:shouldChangeTextInRange:replacementText:.
Edit 1/9/14: only the first space on a line should be ignored, further spaces should be processed as normal (i.e. inserted into the text), ruling out a brute force strip of spaces. Also I'm dealing with a large string (potentially hundreds of thousands of characters) in a text editor (meaning constant user typing), so analyzing the entire string with every keystroke isn't going to be performant.
Upvotes: 1
Views: 7912
Reputation: 1530
Yes, I see it too on my iPad 7.0.3 simulator.
One way to solve it is to add this UITextViewDelegate
method:
- (void)textViewDidChange:(UITextView *)textView
{
// eliminates spaces, including those introduced by autocorrect
if ([textView.text rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]].location != NSNotFound) {
textView.text = [textView.text stringByReplacingOccurrencesOfString:@" " withString:@""];
}
}
It seems that this delegate method is called after autocorrection, just that the in the case you want to prevent (where "Apple" becomes " Apple") the replacement text is " Apple" and not " ". So to modify the implementation to prevent "\n " but allow other " " characters in your text, you could try comparing the first character of text
to " " instead of comparing text
to " ".
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// compare first character to 'space' character by decimal value
if (text.length && [text characterAtIndex:0] == 32) {
// check if previous character is a newline
NSInteger locationOfPreviousCharacter = range.location - 1;
if (locationOfPreviousCharacter < 0 || [textView.text characterAtIndex:locationOfPreviousCharacter] == 10) {
textView.backgroundColor = [UIColor yellowColor];
return NO;
}
}
return YES;
}
Upvotes: 1