I have a UIViewCOntroller
that contains a UITextView
. When the keyboard appears I resize it like this:
#pragma mark - Responding to
A lot of answers already, I found that in my case it's actually much simpler. On keyboardWillShow I adjust the text view's contentInset
and keep the frame full screen. And while scrollRangeToVisible:
is not working for me like for so many others, the scroll view methods (from which UITextView inherits) work just fine. This works for me:
- (void)textViewDidChange:(UITextView *)textView
{
CGRect caret = [_textView caretRectForPosition:_textView.selectedTextRange.end];
[_textView scrollRectToVisible:caret animated:YES];
}
This is what I ended up doing, and something that seems to work:
- (void)textViewKeyboardWillShow:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// self.textViewBottomSpace.constant = NSLayoutConstraint in IB (bottom position)
self.textViewBottomSpace.constant = kbSize.height + 70;
[self.textView setNeedsDisplay];
}
- (void)textViewKeyboardWillHide:(NSNotification *)notification
{
self.textViewBottomSpace.constant = 0;
[self.textView setNeedsDisplay];
}
- (void)scrollCaretToVisible
{
//This is where the cursor is at.
CGRect caretRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.end];
if(CGRectEqualToRect(caretRect, _oldRect))
return;
_oldRect = caretRect;
//This is the visible rect of the textview.
CGRect visibleRect = self.textView.bounds;
visibleRect.size.height -= (self.textView.contentInset.top + self.textView.contentInset.bottom);
visibleRect.origin.y = self.textView.contentOffset.y;
//We will scroll only if the caret falls outside of the visible rect.
if(!CGRectContainsRect(visibleRect, caretRect)) {
CGPoint newOffset = self.textView.contentOffset;
newOffset.y = MAX((caretRect.origin.y + caretRect.size.height) - visibleRect.size.height + 10, 0);
[self.textView setContentOffset:newOffset animated:YES];
}
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
[_caretVisibilityTimer invalidate];
_caretVisibilityTimer = nil;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
self.oldRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.end];
self.caretVisibilityTimer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(scrollCaretToVisible) userInfo:nil repeats:YES];
}
A simpler solution to this problem is to update the text view frame in response to the textViewDidBegingEditing delegate method. For further details, see the following:
How to re-size UITextView when keyboard shown with iOS 7