Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I find portion of my view which isn't covered by the keyboard (UIModalPresenationStyleFormSheet)?

I've got a view controller showing a view with a UITextView, and I want to resize the view when the keyboard appears so that the UITextView isn't covered by the keyboard. I have this working correctly in almost all cases. I'm still seeing some weirdness on the iPad, only when the view controller is presented in ModalPresentationStyleFormSheet, and only in LandscapeRight orientation, as far as I can tell.

Relevant parts of my view controller's -keyboardWillShow:

// We'll store my frame above the keyboard in availableFrame
CGRect availableFrame = self.view.frame;

// Find the keyboard size
NSDictionary *userInfo = [notification userInfo];
NSValue keyboardFrameScreenValue = userInfo[UIKeyboardFrameBeginUserInfoKey];
CGRect keyboardFrameScreen =  [keyboardFrameScreenValue CGRectValue];
CGRect keyboardFrame = [self.view convertRect:keyboardFrameScreen fromView:nil];
CGSize keyboardSize = keyboardFrame.size;

// Figure out how much of my frame is covered by the keyboard
CGRect screenBounds = [self.view convertRect:[UIScreen mainScreen].bounds
                                    fromView:nil];
CGRect myBoundsScreen = [self.view boundsInWindow]; // See below
CGFloat myBottom = myBoundsScreen.origin.y + myBoundsScreen.size.height;
CGFloat keyboardTop = screenBounds.size.height - keyboardSize.height;
CGFloat lostHeight = myBottom - keyboardTop;
availableFrame.size.height -= lostHeight;

-[UIView boundsInWindow]:

- (CGRect)boundsInWindow {
  UIInterfaceOrientation orientation =
    [UIApplication sharedApplication].statusBarOrientation;
  CGRect bounds = [self convertRect:self.bounds toView:self.window];
  if (UIInterfaceOrientationIsLandscape(orientation)) {
    // Swap origin
    CGFloat x = bounds.origin.y;
    bounds.origin.y = bounds.origin.x;
    bounds.origin.x = x;
    // Swap size
    CGFloat width = bounds.size.height;
    bounds.size.height = bounds.size.width;
    bounds.size.width = width;
  }

  return bounds;
}

This works, most of the time. When my app is in user interface orientation LandscapeRight though, the origin I get from -boundsInWindow is quite a bit lower than it should be. What could be causing this?

Thanks for any assistance!

like image 231
Greg Avatar asked Jan 15 '23 19:01

Greg


2 Answers

Will's answer was the right idea but I had to tweak it quite a bit to get it right

extension UIView {
    func heightCoveredByKeyboardOfSize(keyboardSize: CGSize) -> CGFloat {
        let frameInWindow = convertRect(bounds, toView: nil)
        guard let windowBounds = window?.bounds else { return 0 }

        let keyboardTop = windowBounds.size.height - keyboardSize.height
        let viewBottom = frameInWindow.origin.y + frameInWindow.size.height

        return max(0, viewBottom - keyboardTop)
    }
}
like image 121
Cameron Askew Avatar answered Jan 21 '23 13:01

Cameron Askew


Here's how I'm handling the keyboard with iPad form sheets:

- (void)UIKeyboardDidShowNotification:(NSNotification*)aNotification
{
    NSDictionary *userInfo = [aNotification userInfo];
    CGSize keyboardSize = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, [self.view heightCoveredByKeyboardOfSize:keyboardSize], 0.0);

    [UIView animateWithDuration:.25f animations:^{
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;
    }];
}

Category on UIView:

- (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:
            keyboardTop = windowBounds.size.width - keyboardSize.width;
            heightCoveredByKeyboard = CGRectGetMaxX(frameInWindow) - keyboardTop;
            break;
        case UIInterfaceOrientationLandscapeRight:
            keyboardTop = windowBounds.size.width - keyboardSize.width;
            heightCoveredByKeyboard = windowBounds.size.width - frameInWindow.origin.x - keyboardTop;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            keyboardTop = windowBounds.size.height - keyboardSize.height;
            heightCoveredByKeyboard = windowBounds.size.height - frameInWindow.origin.y - keyboardTop;
            break;
        default:
            keyboardTop = windowBounds.size.height - keyboardSize.height;
            heightCoveredByKeyboard = CGRectGetMaxY(frameInWindow) - keyboardTop;
            break;
    }

    return MAX(0.0f,heightCoveredByKeyboard);
}
like image 33
Will Lisac Avatar answered Jan 21 '23 13:01

Will Lisac