The answers posted so far have not worked for me, since I have a pretty deep nested UIViews structure. Also, I had a problem in that some of these answers only work with specific device orientations.
Here is my solution, which I hope will make you spend a little time on this.
My UIViewTextView comes from UIView, is a UITextView delegate, and adds a UITextView after reading some parameters from the XML file for that UITextView (this part of XML is missing here for clarity).
Here is the definition of the private interface:
In the init method, I need to register event handlers:
@implementation UIViewTextView - (id) initWithScrollView:(UIScrollView*)scrollView { self = [super init]; if (self) { contentScrollView = scrollView; // ... tf = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 241, 31)]; // ... configure tf and fetch data for it ... tf.delegate = self; // ... NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(keyboardWasShown:) name: UIKeyboardWillShowNotification object:nil]; [nc addObserver:self selector:@selector(keyboardWasHidden:) name: UIKeyboardWillHideNotification object:nil]; [self addSubview:tf]; } return(self); }
Once this is done, we need to handle the show event. It is called before calling textViewBeginEditing, so we can use it to find out some properties of the keyboard. Essentially, we want to know the height of the keyboard. This, unfortunately, should be taken from its width property in landscape mode:
-(void)keyboardWasShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; CGSize kbSize = kbRect.size; CGRect screenRect = [[UIScreen mainScreen] bounds]; CGFloat sWidth = screenRect.size.width; CGFloat sHeight = screenRect.size.height; UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; if ((orientation == UIDeviceOrientationPortrait) ||(orientation == UIDeviceOrientationPortraitUpsideDown)) { kbHeight = kbSize.height; kbTop = sHeight - kbHeight; } else {
Next, we need to scroll through the page when we start editing. We do it here:
- (void) textViewDidBeginEditing:(UITextView *)textView { /* * Memorize the current scroll position */ currentScrollViewPosition = contentScrollView.contentOffset.y; /* * Memorize the current scroll view height */ currentScrollViewHeight = contentScrollView.frame.size.height; // My top position CGFloat myTop = [self convertPoint:self.bounds.origin toView:[UIApplication sharedApplication].keyWindow.rootViewController.view].y; // My height CGFloat myHeight = self.frame.size.height; // My bottom CGFloat myBottom = myTop + myHeight; // Eventual overlap CGFloat overlap = myBottom - kbTop; /* * If there no overlap, there nothing to do. */ if (overlap < 0) { return; } /* * Calculate the new height */ CGRect crect = contentScrollView.frame; CGRect nrect = CGRectMake(crect.origin.x, crect.origin.y, crect.size.width, currentScrollViewHeight + overlap); /* * Set the new height */ [contentScrollView setFrame:nrect]; /* * Set the new scroll position */ CGPoint npos; npos.x = contentScrollView.contentOffset.x; npos.y = contentScrollView.contentOffset.y + overlap; [contentScrollView setContentOffset:npos animated:NO]; }
When we finish editing, we do this with the reset scroll position:
- (void) textViewDidEndEditing:(UITextView *)textView { CGRect crect = contentScrollView.frame; CGRect nrect = CGRectMake(crect.origin.x, crect.origin.y, crect.size.width, currentScrollViewHeight); [contentScrollView setFrame:nrect]; CGPoint npos; npos.x = contentScrollView.contentOffset.x; npos.y = currentScrollViewPosition; [contentScrollView setContentOffset:npos animated:YES]; [tf resignFirstResponder];
There is no hidden event handler left in the keyboard; we leave it anyway:
-(void)keyboardWasHidden:(NSNotification*)aNotification { }
What is it.
/* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ @end