Search code examples
iosipadframemodalviewcontrolleruikeyboard

iOS: Get top of keyboard point in iPad modal view?


I need to adjust a 'message bar' when the keyboard is shown and am having issues when using iPad modal view controller. The 'message bar' should sit right on top of the keyboard when it is shown, and then at the bottom of the modal when the keyboard is hidden (a la Messages app style).

The problem is I need to get the top most point of the keyboard's frame in terms of the Modal's coordinate system. I found this answer that theoretically seems correct, but doesn't work (How can I find portion of my view which isn't covered by the keyboard (UIModalPresenationStyleFormSheet)?):

FYI When the keyboard is shown, the keyboard's frame in the main window (i.e. 'keyboardFrame') = (-84.0, 526.0, 768.0, 264.0). The keyboard's frame when translated for the modal view controller coordinate system (i.e. 'newSize') = (-168.0, 292.0, 768.0, 264.0)*

// Convert the keyboard rect into the view controller's coordinate system
// The fromView: nil means keyboardRect is in the main window's coordinate system
let newSize = self.view.convertRect(keyboardFrame, fromView: nil)

// And then this is the part that gets covered!
let keyboardCoveredHeight = self.view.bounds.height - newSize.origin.y
self.messageToolbar.bottomConstraint.constant = -keyboardCoveredHeight

enter image description here


Solution

  • I ended up using a familiar category to get the proper keyboard frame in a iPad modal view:

    - (CGFloat)heightCoveredByKeyboardOfSize:(CGSize)keyboardSize
    {
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    CGRect frameInWindow = [self convertRect:self.bounds toView:nil];
    CGRect windowBounds = self.window.bounds;
    
    CGFloat keyboardTop;
    CGFloat heightCoveredByKeyboard;
    
    //Determine height of the view covered by the keyboard relative to current rotation
    
    switch (orientation)
    {
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
            keyboardTop = windowBounds.size.height - keyboardSize.height;
            heightCoveredByKeyboard = windowBounds.size.height - frameInWindow.origin.y - keyboardTop;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
        default:
            keyboardTop = windowBounds.size.height - keyboardSize.height;
            heightCoveredByKeyboard = CGRectGetMaxY(frameInWindow) - keyboardTop;
            break;
    }
    
    return MAX(0.0f,heightCoveredByKeyboard);
    }
    

    along with DAKeyboardControl (for panning):

        // Use [unowned self] in closure for weak reference
        self.view.addKeyboardPanningWithFrameBasedActionHandler(nil, constraintBasedActionHandler: { [unowned self] (keyboardFrameInView, opening, closing) -> Void in
            if opening
            {
                if UIDevice.isIpad()
                {
                    // iPad requires a different method due to use of modal view
                    self.messageToolbar.bottomConstraint.constant = -self.view.heightCoveredByKeyboardOfSize(keyboardFrameInView.size)
                }
                else
                {
                    self.messageToolbar.bottomConstraint.constant = -keyboardFrameInView.size.height
                }
            }
    
            if closing
            {
                self.messageToolbar.bottomConstraint.constant = 0
            }
    
            self.view.updateConstraintsIfNeeded()
            self.view.layoutIfNeeded()
        })