UITextView in iOS7 has been really weird. As you type and are entering the last line of your UITextView, the scroll view doesn\'t scroll to the bottom like it should and it
Heres a modified version of the selected answer by davidisdk.
- (void)textViewDidChange:(UITextView *)textView {
NSRange selection = textView.selectedRange;
if (selection.location + selection.length == [textView.text length]) {
CGRect caretRect = [textView caretRectForPosition:textView.selectedTextRange.start];
CGFloat overflow = caretRect.origin.y + caretRect.size.height - (textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top);
if (overflow > 0.0f) {
CGPoint offset = textView.contentOffset;
offset.y += overflow + 7.0f;
[UIView animateWithDuration:0.2f animations:^{
[textView setContentOffset:offset];
}];
}
} else {
[textView scrollRangeToVisible:selection];
}
}
I was getting a bug that when the textView's content size is larger then the bounds and the cursor is offscreen (such as using a keyboard and pressing the arrow key) the textView wouldn't animate to the text being inserted.
Here is the MonoTouch version of davididsk's most excellent solution (from above).
TextView.SelectionChanged += (object sender, EventArgs e) => {
TextView.ScrollRangeToVisible(TextView.SelectedRange);
};
TextView.Changed += (object sender, EventArgs e) => {
CGRect line = TextView.GetCaretRectForPosition(TextView.SelectedTextRange.Start);
nfloat overflow = line.Y + line.Height -
(TextView.ContentOffset.Y +
TextView.Bounds.Height -
TextView.ContentInset.Bottom -
TextView.ContentInset.Top );
if ( overflow > 0 )
{
// We are at the bottom of the visible text and introduced
// a line feed, scroll down (iOS 7 does not do it)
// Scroll caret to visible area
CGPoint offset = TextView.ContentOffset;
offset.Y+= overflow + 7; // leave 7 pixels margin
// Cannot animate with setContentOffset:animated:
// or caret will not appear
UIView.Animate(0.1,()=> {
TextView.ContentOffset = offset;
});
}
};
Set theViewDelegate to "self" in your .m and use in your .h then add this code to your .m
Will handle BOTH the versions of this glitch that are occurring for going to the next line with text (wrapping or carriage return) and typing... AND going to the next line with just a carriage return and no typing (this code, unlike other's code, will scroll to show the blinking cursor not being clipped in this second glitch scenario)
//!!!*!!****!*!**!*!*!!!MAKE SURE YOU SET DELEGATE AND USE THE <UITEXTVIEWDELEGATE>
-(void)textViewDidChange:(UITextView *)textView {
[theTextView scrollRangeToVisible:[textView selectedRange]];//resizing textView frame causes text itself "content frame?" to still go below the textview frame and get clipped... auto-scrolling must be implimented. (iOS7 bug)
}
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if (([text isEqualToString:@"\n"]) && (range.location == textView.text.length)) {//"return" at end of textView
[textView scrollRectToVisible:CGRectMake(5,5,5,999999999999999999) animated:NO];//for some reason the textViewDidChange auto scrolling doesnt work with a carriage return at the end of your textView... so I manually set it INSANELY low (NOT ANIMATED) here so that it automagically bounces back to the proper position before interface refreshes when textViewDidChange is called after this.
}
return YES;
}
The solution I found here was to add a one line fix after you create a UITextView:
self.textview.layoutManager.allowsNonContiguousLayout = NO;
This one line fixed three issues I had creating a UITextView-based code editor with syntax highlighting on iOS7:
Note, I did resize the whole UITextView when the keyboard is shown/hidden.
If you are using StoryBoard then this behavior can also happen if you left AutoLayout on (as it is by default) and did not set top/bottom constraints for your UITextView. Check the File Inspector to see what your AutoLayout status is...
Try implementing the -textViewDidChangeSelection:
delegate method from the UITextViewDelegate like this:
-(void)textViewDidChangeSelection:(UITextView *)textView {
[textView scrollRangeToVisible:textView.selectedRange];
}