滚动到iOS 7中不稳定的UITextView底部
下面的代码将在iOS 7.0中正常工作。 在iOS 7中,UITextView正在更新时,滚动会变得不稳定和不稳定。 我不确定这是否是iOS 7中的错误,或者我做错了什么。
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
这显然是一个iOS 7的错误。 这是一个解决方法,直到苹果修复它。 解决方法基本上是通过从头创build一个NSTextStorage
和NSLayoutManager
实例化一个UITextView
。 苹果公司一定忘了在UITextView
初始化方法中初始化一些东西。 我提交了一个错误报告,我希望你也能做到。
// ios7 bug fix // check if the device is running iOS 7.0 or later NSString *reqSysVer = @"7.0"; NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending); if (osVersionSupported) { NSTextStorage* textStorage = [[NSTextStorage alloc] init]; NSLayoutManager* layoutManager = [NSLayoutManager new]; [textStorage addLayoutManager:layoutManager]; NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size]; [layoutManager addTextContainer:textContainer]; yourTextView = [[UITextView alloc] initWithFrame:someFrameForYourTextView textContainer:textContainer]; // if using ARC, remove these 3 lines [textContainer release]; [layoutManager release]; [textStorage release]; } else { yourTextView = [[UITextView alloc] initWithFrame:someFrameForYourTextView]; }
这在iOS7中适用于我。
-(void) scrollToBottom { [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)]; [textView setScrollEnabled:NO]; [textView setScrollEnabled:YES]; }
iOS 7中有两个问题可以解释你的问题:
- contentOffset在iOS 7中并不总是最新的。
- scrollRangeToVisible:不会滚动到文本视图结尾的空行。
解决scheme可能是:
-(void)scrollOutputToBottom { CGRect caretRect = [textView caretRectForPosition:textView.endOfDocument]; [textView scrollRectToVisible:caretRect animated:NO]; }
尝试这个:
// Don't forget to set textView's delegate -(void)textViewDidChangeSelection:(UITextView *)textView { [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)]; }
对于那些使用Swift的人,我在这里发布与RawMean相同的答案(再次感谢!)。 正如我写的(2014年12月),这个问题仍然存在于iOS 8.1和他的解决scheme完美的工作…
var textView: UITextView! var textStorage: NSTextStorage! var layoutManager: NSLayoutManager! var textContainer: NSTextContainer! override func viewDidLoad() { textStorage = NSTextStorage() layoutManager = NSLayoutManager() textStorage.addLayoutManager(layoutManager) let newTextViewRect = view.bounds let containerSize = CGSize(width: newTextViewRect.width, height: CGFloat.max) textContainer = NSTextContainer(size: containerSize) layoutManager.addTextContainer(textContainer) textView = UITextView(frame: newTextViewRect, textContainer: textContainer) textView.delegate = self view.addSubview(textView) } override func viewDidLayoutSubviews() { textView.frame = view.bounds }
和我使用scrollRangeToVisible方法滚动顺利在文本添加底部…
let length = countElements(textView.text) let range:NSRange = NSMakeRange(length - 1, 1) textView.scrollRangeToVisible(range)
基本上setScrollEnabled = YES需要在layoutSubviews被调用之前设置。 它为我工作。
这对我行得通。 参考: UITextView setText不应该跳转到ios8的顶部
self.textView.layoutManager.allowsNonContiguousLayout = NO; self.textView.text = fileContent; if(fileContent.length > 1) { NSRange range = NSMakeRange(self.textView.text.length - 1, 1); [self.textView scrollRangeToVisible:range]; }
Swift 2.0 – IOS 8
这基本上是上面dklt的答案的Swift 2.0版本。 以前我没有使用scrollEnabled
的2行使用相同的方法。 大多数情况下,它工作正常。 但是,几乎同时快速连续调用scrollToBottom()
时,有时不起作用。
scrollEnabled
的2行没有多大意义,但是在添加它们之后,该方法始终如一地工作 !
注意:我试图把scrollEnabled
的两行放在scrollEnabled
之前或之后的不同位置,就像在dklt的回答的注释中所build议的那样。
只有dklt的原始解决scheme适用于我。 其余的不是。
func scrollToBottom() { let range:NSRange = NSMakeRange(self.textView.text.characters.count - 1, 1) self.textView.scrollRangeToVisible(range) self.textView.scrollEnabled = false self.textView.scrollEnabled = true }
请尝试这个解决scheme
-(void) scrollToBottom { [textView setContentOffset:CGPointMake(0.0, textView.contentSize.height) animated:YES]; }