Resize a view when a keyboard appears (iOS)

bkocik picture bkocik · Apr 16, 2013 · Viewed 22.4k times · Source

I realize there are many similar solutions, such as TPKeyboardAvoiding, Apple's famous solution, and various suggestions involving the use of UIScrollView. In my case, I need to resize a view to accommodate the keyboard rather than scroll or move it. This solution comes closest to what I'm trying to achieve, so it was my basis. However I'm having an issue making things work in landscape mode. My method that resizes the view when the keyboard appears is this:

- (void)keyboardWillShow:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];

    CGRect keyboardFrame = [[self textField].superview convertRect:[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
    CGRect statusBarFrame = [[self textField].superview convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil];

    CGRect bounds = [self textField].superview.bounds;    
    CGRect newFrame = CGRectMake(0.0, 0.0, bounds.size.width, keyboardFrame.origin.y + statusBarFrame.size.height);
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        [self textField].superview.frame = newFrame;
    } completion:nil];
}

This works perfectly in portrait mode.

enter image description here

However, in landscape mode, the view resizes from left-to-right or right-to-left depending upon in which direction the device was rotated, rather than from the bottom up.

enter image description here

Clearly there is something wrong with how I'm using coordinates, and some frame of reference isn't what I think it is when in landscape mode, but I'm having a heck of a time sorting out how to resolve it. I've tried converting all kinds of things with -convertRect: but nothing I'm trying is getting me anywhere.

I'm really hoping someone who's less confused by all these rectangles and how they change when orientation changes can spot what I'm doing wrong and what I need to do to get this right. For reference, I've created a project showing the simplest case that reproduces the problem I'm having.

Answer

Vitaly Berg picture Vitaly Berg · Apr 16, 2013

I do not advise you to resize root view for your view controller, you can create contentView and add to view of view controller. You can change size of this contentView as below (I don't use autolayouting):

- (void)keyboardWillShow:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        self.contentView.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
    } completion:nil];
}

- (void)keyboardWillHide:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        self.contentView.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
    } completion:nil];
}