In previous versions of iOS, my UITextView
will scroll to the bottom using
[displayText scrollRangeToVisible:NSMakeRange(0,[displayText.text length])];
or
CGFloat topCorrect = displayText.contentSize.height -[displayText bounds].size.height;
topCorrect = (topCorrect<0.0?0.0:topCorrect);
displayText.contentOffset = (CGPoint){.x=0, .y=topCorrect};
But the former will now have the weird effect of starting at the top of a long length of text and animating the scroll to the bottom each time I append text to the view. Is there a way to pop down to the bottom of the text when I add text?
textView.scrollEnabled = NO;
[textView scrollRangeToVisible:NSMakeRange(textView.text.length - 1,0)];
textView.scrollEnabled = YES;
This really works for me in iOS 7.1.2.
For future travelers, building off of @mikeho's post, I found something that worked wonders for me, but is a bit simpler.
1) Be sure your UITextView
's contentInset
s are properly set & your textView is already firstResponder()
before doing this.
2) After my the insets are ready to go, and the cursor is active, I call the following function:
private func scrollToCursorPosition() {
let caret = textView.caretRectForPosition(textView.selectedTextRange!.start)
let keyboardTopBorder = textView.bounds.size.height - keyboardHeight!
// Remember, the y-scale starts in the upper-left hand corner at "0", then gets
// larger as you go down the screen from top-to-bottom. Therefore, the caret.origin.y
// being larger than keyboardTopBorder indicates that the caret sits below the
// keyboardTopBorder, and the textView needs to scroll to the position.
if caret.origin.y > keyboardTopBorder {
textView.scrollRectToVisible(caret, animated: true)
}
}
I believe this is a bug in iOS 7. Toggling scrollEnabled on the UITextView seems to fix it:
[displayText scrollRangeToVisible:NSMakeRange(0,[displayText.text length])];
displayText.scrollEnabled = NO;
displayText.scrollEnabled = YES;
I think your parameters are reversed in NSMakeRange
. Location is the first one, then how many you want to select (length).
NSMakeRange(0,[displayText.text length])
...would create a selection starting with the 0th (first?) character and going the entire length of the string. To scroll to the bottom you probably just want to select a single character at the end.
This is working for me in iOS SDK 7.1 with Xcdoe 5.1.1.
[textView scrollRangeToVisible:NSMakeRange(textView.text.length - 1,0)];
textView.scrollEnabled = NO;
textView.scrollEnabled = YES;
I do this as I add text programmatically, and the text views stays at the bottom like Terminal or command line output.
The best way is to set the bounds for the UITextView
. It does not trigger scrolling and has an immediate effect of repositioning what is visible. You can do this by finding the location of the caret and then repositioning:
- (void)userInsertingNewText {
UITextView *textView;
// find out where the caret is located
CGRect caret = [textView caretRectForPosition:textView.selectedTextRange.start];
// there are insets that offset the text, so make sure we use that to determine the actual text height
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;
// only set the offset if the caret is out of view
if (textViewHeight < caret.origin.y) {
[self repositionScrollView:textView newOffset:CGPointMake(0, caret.origin.y - textViewHeight)];
}
}
/**
This method allows for changing of the content offset for a UIScrollView without triggering the scrollViewDidScroll: delegate method.
*/
- (void)repositionScrollView:(UIScrollView *)scrollView newOffset:(CGPoint)offset {
CGRect scrollBounds = scrollView.bounds;
scrollBounds.origin = offset;
scrollView.bounds = scrollBounds;
}