The following code will work fine in iOS < 7.0. In iOS 7 the scrolling will be choppy and erratic while the UITextView is updating. I'm not sure if this is a bug in iOS 7, or I am doing something wrong.
TestController.h
//TODO: Add UITextView in storyboard and tie to textView outlet
#define MAX_TEXT_VIEW_CHARACTERS 1000
@interface TestController : UIViewController {
NSMutableString *_outputText;
NSTimer *_outputTimer;
}
@property (strong, nonatomic) IBOutlet UITextView *textView;
@end
TestController.m
@implementation TestController
@synthesize textView;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
_outputText = [NSMutableString stringWithCapacity:MAX_TEXT_VIEW_CHARACTERS];
_outputTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(outputLine:) userInfo:nil repeats:YES];
}
-(void)outputLine:(NSTimer *) theTimer {
static int i = 0;
//Run this 100 times
if (i > 99) {
[_outputTimer invalidate];
return;
}
[self outputToScreen:[NSString stringWithFormat:@"Some string %d\r", ++i]];
}
-(void)outputToScreen:(NSString *)str {
if (!str || !str.length) return; //Nothing to output
NSInteger outputTextSize = _outputText.length;
[_outputText appendString:str];
if (outputTextSize > MAX_TEXT_VIEW_CHARACTERS)
[_outputText deleteCharactersInRange:NSMakeRange(0, outputTextSize - MAX_TEXT_VIEW_CHARACTERS)];
self.textView.text = _outputText;
[self scrollOutputToBottom];
}
-(void)scrollOutputToBottom {
CGPoint p = [textView contentOffset];
[textView setContentOffset:p animated:NO];
[textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)];
}
@end
Basically setScrollEnabled = YES need to be set before layoutSubviews get called. It worked for me.
This works for me in iOS7.
Swift 2.0 - IOS 8
This is basically a Swift 2.0 version of dklt's answer above. Previously I was using the same method without the 2 lines of
scrollEnabled
. Most of the time it works fine. However, whenscrollToBottom()
is called in quick succession at almost the same time, it doesn't works sometimes.The 2 lines of
scrollEnabled
doesn't makes much sense, but after adding them the method works consistently!Note: I have tried to put the 2 lines of
scrollEnabled
in various position before or after thescrollRangeTovisible
, as was suggested in dklt's answer's comments...ONLY dklt's original solution works for me. The rest doesn't.
That works for me. Reference: UITextView setText should not jump to top in ios8
This is obviously an iOS 7 bug. Here is a workaround until apple fixes it. The workaround is basically instantiates a
UITextView
by creating anNSTextStorage
andNSLayoutManager
from scratch. Apple must have forgotten to initialize something inUITextView
initialization method. I filed a bug report and I hope you do too.There are two problems in iOS 7 that could explain your problem:
The solution could be: