7

I've looked for a solution to this all morning, but have yet to find something that works.

I have a text view that has some existing fixed text in it that I don't want the user to be able to modify. In this case, each of my text views start with "1. ", "2. ", etc. The idea being that the text they entered will be numbered for something I'm doing later.

I don't want the user to be able to delete this text (it is essentially "permanent"). I also don't want to allow them to start adding text in the middle of this pre-text.

To handle this, I have done:

-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text 
{
    if (range.location < 3) return NO;

    return YES;
}

This works great, except that if the user touches anywhere in my "1. ", "2. ", etc. parts of the view, it will set the cursor there, which then prevents the user from typing text because of the range location check. What I want to do in this case is set the cursor (perhaps in textViewDidBeginEditing) to the end of the text in the view. However, regardless of what combination of selectedRange I use, I just can't get the darn cursor to move to the end. Any help would be greatly appreciated.

Rok Jarc
  • 18,235
  • 9
  • 64
  • 120
Jason
  • 4,977
  • 4
  • 15
  • 11
  • 1
    An even easier way would be to put your numbers in a label right up against your text view so that they look like they are part of the same sentence. Then, they will only be able to change the appropriate part. – lnafziger Jul 27 '13 at 23:36

6 Answers6

11

To move the cursor to the end

textView.selectedRange = NSMakeRange([textView.text length], 0);

or to move the cursor to after the third character

textView.selectedRange = NSMakeRange(3, 0);

Another, maybe better, approach might be to clear the first three characters out when the user starts editing, then add them back in once editing is over.

trapper
  • 10,375
  • 6
  • 31
  • 74
  • This is exactly what I tried to do. However it appears that regardless of if I set selectedRange, the cursor always puts itself where the view was touched. Well, it will put the cursor somewhere in the middle of the text if the user touches where there is text, otherwise it will put the cursor at the end if the user touches in an empty area. It seems like there is an extra step at the end that overrides the range with touch location. – Jason May 26 '12 at 14:27
  • check my answer [here](http://stackoverflow.com/questions/8891072/how-to-set-the-position-of-the-cursor-in-uitextview) involving `performSelector:withObject:afterDelay` I know this is late but... whatever HTH – Cashew Dec 26 '12 at 07:55
9

It's late but i found working solution for this in some blog . it needs a little hack

- (void) textViewDidBeginEditing:(UITextView*)textview
{
   [self performSelector:@selector(placeCursorAtEnd:) withObject:textview afterDelay:0.01];
}

- (void)placeCursorAtEnd:(UITextView *)textview
{
     NSUInteger length = textview.text.length;

    textview.selectedRange = NSMakeRange(length, 0);
}
Shaik Riyaz
  • 10,085
  • 7
  • 48
  • 67
  • hi, i append image as NSAttachment using "messageInputBar.inputTextView.textStorage.insert(attString, at: messageInputBar.inputTextView.selectedRange.length)", but the curso always in first character and the placeholder text still show – famfamfam Jun 19 '20 at 09:49
5

You could consider registering to the UIKeyboardWillShowNotification and upon receiving the notification, set the textview's userInteractionEnabled to NO.

Also, implement the shouldChangeTextInRange method in a way that if replacementText is equal to the string @"" you don't change the text (@"" meaning the user is tapping backspace). Restore user interaction when the user finishes editing the text and there you go.

Good luck!

James Zaghini
  • 3,701
  • 3
  • 42
  • 57
Stavash
  • 14,032
  • 5
  • 50
  • 79
  • This seems to have been the best way to do this. Kind of stupid that setting range does not seem to be working. – Jason May 26 '12 at 14:53
3

I was trying to make a currency field. I did not want the user pressing all over the field and potentially deleting formatted text. The easiest way I found to keep the cursor at the end is to do the following in a subclass of UITextField

-(void) setSelectedTextRange:(UITextRange *)selectedTextRange{

    [super setSelectedTextRange:selectedTextRange];
    self.text = self.text;
}
James Zaghini
  • 3,701
  • 3
  • 42
  • 57
datinc
  • 3,194
  • 2
  • 21
  • 32
0

This method hide autocorrection & keyboard not jump.

- (void)rejectAutoCorrectSuggestionInTextView:(UITextView *)textView
{
    if ([textView isFirstResponder])
    {
        NSString *original = textView.text;
        NSRange originalRange = textView.selectedRange;
        CGPoint originalOffset = textView.contentOffset;

        [UIView animateWithDuration:.00001 animations:^{
            textView.text = [textView.text stringByAppendingString:@"|"];
            NSRange range;
            range.location = textView.text.length-1;
            range.length = 0;
            textView.selectedRange = range;
            textView.text = [textView.text substringToIndex:textView.text.length - 1];
        }];

        NSString *final = textView.text;

        if (![original isEqualToString:final])
        {
            textView.text = original;
            textView.selectedRange = originalRange;
            [textView setContentOffset:originalOffset animated:NO];
        }
    }
}
Nuzhdin Vladimir
  • 1,373
  • 17
  • 29
0
extension UITextView {
    func moveCoursoreToEnd(){
        selectedTextRange = textRange(from:endOfDocument, to: endOfDocument)
    }
}
dr OX
  • 4,423
  • 1
  • 13
  • 8