Reputation: 34780
I am trying to scroll my text view up when keyboard is presented. I am trying to follow Apple's own tutorial at https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html. Instead of scroll views and frames I am using autolayout, but the general idea is same (subscribing to keyboard notifications, and animating the layout constraints accordingly). However, when I display the keyboard, there is a gap between the text view and the keyboard: (this is a screenshot from Turkish keyboard, but the same gap, marked with red, is present in all keyboards installed, including custom ones). (Screenshot from iPhone 6 Plus, but the issue is also present on other screen sizes too)
I've seen can't get correct value of keyboard height in iOS8 and I've tried using both UIKeyboardFrameEndUserInfoKey
and UIKeyboardFrameBeginUserInfoKey
but they all result in the same gap. I've tried attaching UIKeyboardWillShowNotification
and on UIKeyboardDidShowNotification
but still, I'm getting the same gap. I think the gap is related to suggestions on some keyboards on iOS 8, but it shouldn't report the keyboard size with suggestions when suggestions is not present.
Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self registerForKeyboardNotifications];
}
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGRect kb = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
float height = kb.size.height;
sendZoneBottomConstraint.constant = height;
[UIView animateWithDuration:.2 animations:^{
[self.view layoutIfNeeded];
}];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
sendZoneBottomConstraint.constant = 0;
[UIView animateWithDuration:.2 animations:^{
[self.view layoutIfNeeded];
}];
}
sendZoneBottomConstraint
is that bottom-most view's bottom spacing to the bottom layout guide.
UPDATE: I've tried changing the keyboard rectangle from window coordinates to my view's coordinates but it didn't change anything. Here is what I tried:
CGRect kb = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
kb = [self.view.window convertRect:kb toView:self.view];
float height = kb.size.height;
UPDATE, VOL 2: I've also seen iOS 8 Orientation change: Keyboard frame does not display correctly but I'm experiencing the issue also on iPhone 5s iOS 7.1 Simulator, so it's not an iOS 8-only issue. How can I solve this problem? I definitely don't want to hard code any keyboard height values in iOS 8 world.
UPDATE, VOL 3: I've also tried it with English keyboard with suggestions both on and off. It still appears with respect to the total size of the keyboard, so it's not about the suggestions/autocomplete view:
Upvotes: 19
Views: 6584
Reputation: 17902
For robust keyboard height calculation you can use the following:
Note: I borrowed some logic from IQKeyboard for this solution.
CGRect kbFrame = [[aNotification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect screenSize = [[UIScreen mainScreen] bounds];
CGRect intersectRect = CGRectIntersection(kbFrame, screenSize);//Calculating actual keyboard displayed size, keyboard frame may be different when hardware keyboard is attached (Bug ID: #469) (Bug ID: #381)
CGSize kbSize;
if (CGRectIsNull(intersectRect)) {
kbSize = CGSizeMake(screenSize.size.width, 0);
} else {
kbSize = intersectRect.size;
}
//
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (rootViewController) {
if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController;
UIViewController *nextRootViewController = [[navigationController viewControllers] lastObject];
if (nextRootViewController) {
rootViewController = nextRootViewController;
continue;
} else {
break;
}
}
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabBarController = (UITabBarController *)rootViewController;
UIViewController *nextRootViewController = tabBarController.selectedViewController;
if (nextRootViewController) {
rootViewController = nextRootViewController;
continue;
} else {
break;
}
}
if (!rootViewController.presentedViewController) {
break;
}
rootViewController = (UIViewController *)rootViewController.presentedViewController;
}
//
CGFloat navigationBarAreaHeight = [[UIApplication sharedApplication] statusBarFrame].size.height + rootViewController.navigationController.navigationBar.frame.size.height;
CGFloat layoutAreaHeight = rootViewController.view.layoutMargins.top;
CGFloat topLayoutGuide = MAX(navigationBarAreaHeight, layoutAreaHeight);
CGFloat bottomLayoutGuide = rootViewController.view.layoutMargins.bottom;
float magicNumber = 5;//Apple Constant
//
float keyboardHeight = kbSize.height-topLayoutGuide-bottomLayoutGuide+magicNumber;
Upvotes: -1
Reputation: 5102
Maybe you are using a tab bar controller, if yes, then when u margin the view after keyboard was shown, calculate the margin bottom without tab bar height.
You can find the tab bar height using:
self.tabBarController?.tabBar.frame.height
Upvotes: 25