30

I have an UIView and I add a editable UITextView to it,

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(5, 5, 219, 47)];
[self addSubview:textView];
textView.font = [UIFont systemFontOfSize:14];

When I type it doesn't go down automatic. Anybody got an idea?

rptwsthi
  • 10,094
  • 10
  • 68
  • 109
Andy Jacobs
  • 15,187
  • 13
  • 60
  • 91

9 Answers9

52

Just figured out that you must use a length > 0. Ie

NSRange range = NSMakeRange(textView.text.length - 1, 1);
[textView scrollRangeToVisible:range];

Worked for me anyway.

Martin Wickman
  • 19,662
  • 12
  • 82
  • 106
  • 1
    Thanks, this was helpful. You also need to check if textView.text.length > 0. – Z S Apr 10 '10 at 18:21
  • Note that this will cause the textView to scroll to the bottom. It's not a great idea to put this in UITextView's textViewDidChange: delegate; if you are editing at the top of the textview, it'll get scrolled to the bottom, which is not what the user would expect. – Z S Apr 18 '14 at 01:53
  • 1
    tried different solutions but this is the one worked like a charm – coder Jul 24 '14 at 06:00
  • @ZS I met this issue when using this code. Is there any way to get rid of this issue ? – Zigii Wong Sep 25 '15 at 02:59
  • Use something like this: http://stackoverflow.com/questions/19259886/uitextview-cursor-not-positioning-properly-when-editing-in-ios-7-why/19298022#19298022 – Z S Sep 25 '15 at 17:13
11

To scroll to the end of the buffer I tried

[textView scrollRangeToVisible:NSMakeRange([textView.text length]-1, 1)];

But nothing happened. Instead this works

textView.selectedRange = NSMakeRange(textView.text.length - 1, 0);
Frank Hintsch
  • 560
  • 8
  • 14
8

I think you'll have to do

[textView scrollRangeToVisible:[textView selectedRange]];

in textDidChange.

Can Berk Güder
  • 109,922
  • 25
  • 130
  • 137
5

When adding text to a text box programmatically, I found I also needed to add "[textView layoutIfNeeded]" to set things up before the new scroll position could be calculated correctly.

for example:

[newString appendFormat:@"%@\n",addText];
textView.text = newString;
[textView layoutIfNeeded];
NSRange range = NSMakeRange(textView.text.length - 2, 1); //I ignore the final carriage return, to avoid a blank line at the bottom
[textView scrollRangeToVisible:range]

Without this addition the textbox would sometimes not scroll, or would scroll several lines every time a single line of data was added.

Peter Johnson
  • 3,764
  • 1
  • 23
  • 27
  • This worked for me: `[textView layoutIfNeeded]; [textView scrollRangeToVisible:NSMakeRange(0, 0)];` – mehdok Feb 19 '16 at 18:12
2

Swift 2.2. It works for me

func textViewDidChange(textView: UITextView) {

   let bottomOffset = CGPointMake(0, textView.contentSize.height - textView.bounds.size.height)
   textView.setContentOffset(bottomOffset, animated: true)
}
Włodzimierz Woźniak
  • 3,106
  • 1
  • 26
  • 23
  • It seems to work when the UITextView is larger than its content, but as soon as the content grows larger than the size on the screen, it's no longer scrolling for me. – lionello Apr 25 '16 at 16:34
1

I found that if the text added to the UITextView contained carriage returns, then the textview would not scroll correctly.

I added the logic as follows to allow the bounds to be correctly calculated before scrolling to range.

BOOL autoscroll = NO;

//I added a 10 px buffer here to allow for better detection as the textview is auto populated 
if (textView.contentOffset.y >= (textView.contentSize.height - textView.frame.size.height - 10))
{
    autoscroll = YES;
}

[textView setText:messageString];
[textView layoutSubviews];

if(autoscroll) {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),     dispatch_get_main_queue(), ^{
        [textView scrollRangeToVisible:NSMakeRange(textView.text.length - 1, 1)];
    });
}
Matthew Cawley
  • 2,828
  • 1
  • 31
  • 42
0

This works:

- (void)textViewDidChange:(UITextView *)textView {
    if (_moveToBottom) {
        int y = textView.contentSize.height - textView.frameHeight + self.textView.contentInset.bottom + self.textView.contentInset.top;
        if(y > 0) {
            [textView setContentOffset:CGPointMake(0, y) animated:YES];
        }
        _moveToBottom = NO;
    }
    else {
        [textView scrollRangeToVisible:NSMakeRange([textView.text length]-1, 1)];
    }
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    if ([text isEqualToString:@"\n"] && range.location == [textView.text length]) {
        _moveToBottom = YES;
    }
    return YES;
}
Everton Cunha
  • 1,017
  • 8
  • 10
0

Use contentOffset, it will automatically scroll to down

textView.contentOffset = CGPointMake(0, textView.contentSize.height - textView.frame.size.height);
Nazik
  • 8,696
  • 27
  • 77
  • 123
0

if found a solution

i put the textview into a view and set the view to clipToBounds = YES then i put the textView to a height of 70

that fixed the problem.

very strange solution, but it finally works :)

Andy Jacobs
  • 15,187
  • 13
  • 60
  • 91
  • If 70 is lower than your UITextView's original height then it gets clipped to that value an probably by coincidence this is exactly what it takes for your case to "autoscroll" to the last line. It's a little too hackish :) – Mihai Damian Nov 27 '09 at 14:41