Stop UITextView from jumping when programmatically

2020-02-09 06:50发布

I have to update a small amount of text in a scrolling UITextView. I'll only be inserting a character where the cursor currently is, and I'll be doing this on a press of a button on my navigation bar.

My problem is that whenever I call the setText method of the text view, it jumps to the bottom of the text. I've tried using contentOffset and resetting the selectedRange but it doesn't work! Here's my example:

// Remember offset and selection
CGPoint contentOffset = [entryTextView contentOffset];
NSRange selectedRange = [entryTextView selectedRange];
// Update text
entryTextView.text = entryTextView.text;
// Try and reset offset and selection
[entryTextView setContentOffset:contentOffset animated:NO];
[entryTextView setSelectedRange: selectedRange];

Is there any way you can update the text without any scroll movement at all... as if they'd just typed something on the keyboard?

Edit:

I've tried using the textViewDidChange: delegate method but it's still not scrolling up to the original location.

- (void)textViewDidChange:(UITextView *)textView {
    if (self.programChanged) {
        [textView setSelectedRange:self.selectedRange];
        [textView setContentOffset:self.contentOffset animated:NO];
        self.programChanged = NO;
    }
}

- (void)changeButtonPressed:(id)sender {
    // Remember position
    self.programChanged = YES;
    self.contentOffset = [entryTextView contentOffset];
    self.selectedRange = [entryTextView selectedRange];
    // Update text
    entryTextView.text = entryTextView.text;
}

13条回答
霸刀☆藐视天下
2楼-- · 2020-02-09 07:16

If you use iPhone 3.0 or later, you can solve this problem:

textView.scrollEnabled = NO;

//You should know where the cursor will be(if you update your text by appending/inserting/deleting you can know the selected range) so keep it in a NSRange variable.

Then update text:
textView.text = yourText;

textView.scrollEnabled = YES;
textView.selectedRange = range;//you keep before

It should work now (no more jumping)

Regards Meir Assayag

查看更多
够拽才男人
3楼-- · 2020-02-09 07:16

In order to edit the text of a UITextView, you need to update it's textStorage field:

[_textView.textStorage beginEditing];

NSRange replace = NSMakeRange(10, 2); //enter your editing range
[_textView.textStorage replaceCharactersInRange:replace withString:@"ha ha$ "];

//if you want to edit the attributes
NSRange attributeRange = NSMakeRange(10, 5); //enter your editing attribute range
[_textView.textStorage addAttribute:NSBackgroundColorAttributeName value:[UIColor greenColor] range:attributeRange];

[_textView.textStorage endEditing];

Good luck

查看更多
Evening l夕情丶
4楼-- · 2020-02-09 07:16

Not so elegant solution- but it works so who cares:

- (IBAction)changeTextProgrammaticaly{
     myTextView.text = @"Some text";
     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(rewindOffset) userInfo:nil repeats:NO];
}

- (void)rewindOffset{
    [myTextView setContentOffset:CGPointMake(0,0) animated: NO];
}
查看更多
Juvenile、少年°
5楼-- · 2020-02-09 07:18

I hit a a similar, if not the same, problem in IOS9. Changing the characteristics of some text to, say, BOLD caused the view to scroll the selection out of sight. I sorted this by adding a call to scrollRangeToVisible after the setSelectedRange:

    [self setSelectedRange:range];
    [self scrollRangeToVisible:range];
查看更多
该账号已被封号
6楼-- · 2020-02-09 07:19

Take a look at the UITextViewDelegate, I believe the textViewDidChangeSelection method may allow you to do what you need.

查看更多
Lonely孤独者°
7楼-- · 2020-02-09 07:25

Building on Meir's suggestion, here's code that removes the selection programmatically (yes I know there's a selection menu button that does it too, but I'm doing something a bit funky) without scrolling the text view.

NSRange selectedRange = textView.selectedRange;
textView.scrollEnabled = NO;
// I'm deleting text. Replace this line with whatever insertions/changes you want
textView.text = [textView.text
                stringByReplacingCharactersInRange:selectedRange withString:@""];
selectedRange.length = 0;
// If you're inserting text, you might want to increment selectedRange.location to be
// after the text you inserted
textView.selectedRange = selectedRange;
textView.scrollEnabled = YES;
查看更多
登录 后发表回答