How can I find a part of my view that is not covered by the keyboard (UIModalPresenationStyleFormSheet)?

I have a view controller showing a view with a UITextView, and I want to resize the view when the keyboard appears so that the UITextView is not covered by the keyboard. I work correctly in all cases. I still see some oddities on the iPad only when the view controller is presented in the ModalPresentationStyleFormSheet and only in the LandscapeRight orientation, as far as I can tell.

The relevant parts of the controller of my kind are -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; } 

It works, most of the time. When my application is in the LandscapeRight UI orientation, although the origin I get from -boundsInWindow is slightly lower than it should be. What could be the reason for this?

Thanks for any help!

+4
source share
3 answers

The answer would be the right idea, but I had to tweak it a bit to figure it out.

 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) } } 
+4
source

Here's how I handle the keyboard with iPad 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 by 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); } 
+2
source

I think I found a pretty decent answer. You can use the convertRect:fromView: method for UIView to convert coordinate systems.

In fast code, the selector that calls UIKeyboardNotification looks something like this:

 func keyboardWasShown(notification: NSNotification) { let info = notification.userInfo! let keyboardRect = (info[UIKeyboardFrameEndUserInfoKey]! as NSValue).CGRectValue() // Convert the keyboard rect into the view controller coordinate system // The fromView: nil means keyboardRect is in the main window coordinate system let newSize = self.view.convertRect(keyboardRect, fromView: nil) // And then this is the part that gets covered! let keyboardCoveredHeight = self.view.bounds.height - newSize.origin.y // Note: you may have to use self.navigationController!.view.bounds.height if // you've wrapped your view in a navigation controller because this will // include the height of the navigation bar // You can then adjust the content inset of the text view accordingly textView.scrollIndicatorInsets.bottom = keyboardCoveredHeight textView.contentInset.bottom = keyboardCoveredHeight } 
+1
source

All Articles