Search code examples
iosswiftobjective-cautolayoutios8

iOS 8 Orientation change: Keyboard frame does not display correctly


This is only an iOS 8 problem, the keyboard displays correctly in iOS 7 with device orientation change. My application supports both portrait and landscape orientation and uses autolayout.

If I push a UIViewController subclass that contains a UITextField subclass onto a navigation stack and the UITextField becomes the first responder in portrait orientation then the default keyboard displays correctly. However, if I rotate the device to landscape orientation then the UIViewController subview layouts are displayed correctly but the keyboard is displayed in the top center of the screen. The keyboard's orientation is correct for landscape orientation but it's frame width is the same width as expected for portrait orientation. If I set the app orientation to only landscape orientation then the keyboard does not display correctly. This is only a problem for iOS 8 orientation change.


Solution

  • Prior to iOS 8, the keyboard's location and width/height were always relative to portrait orientation when reported to the app. (e.g. Landscape's keyboard width is in the y direction, ~352 pixels on an iPad.) As of iOS 8, this has been updated to always have (0,0) at the top left of your (physical) view and the width/height reflect the x/y orientation you would normally expect outside of iOS. If you were previously positioning your keyboard via something like keyboardDidShow's [notification userInfo], you are going to get numbers that don't quite make sense. You can use something along these lines to take into account the pre-iOS8 idiosyncrasies:

    - (void)keyboardDidShow: (NSNotification *) notification{
    
        NSDictionary *keyboardInfo = [notification userInfo];
        CGSize keyboardSize = [[keyboardInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
        float height, width;
        if(UIInterfaceOrientationIsPortrait(orientation)){
            width = keyboardSize.width;
            height = keyboardSize.height;
        } else {
            if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1){
                width = keyboardSize.height;
                height = keyboardSize.width;
            } else {
                width = keyboardSize.width;
                height = keyboardSize.height;
            }
        }
    
        // Remainder of function
    }
    

    Which can be refactored down to...

    - (void)keyboardDidShow: (NSNotification *) notification{
    
        NSDictionary *keyboardInfo = [notification userInfo];
        CGSize keyboardSize = [[keyboardInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
        float width = keyboardSize.width;
        float height = keyboardSize.height;
        if(!UIInterfaceOrientationIsPortrait(orientation) && (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1)){
            width = keyboardSize.height;
            height = keyboardSize.width;
        }
    
        // Remainder of function
    }
    

    Also, the 8.1 update fixed several landscape/rotation bugs likely related to the above change. Grab the update and see if that solves your issue.