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!
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)
}
}
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With