I have an observed method that trigger when the soft keyboard is shown. It works fine, but for some reason the height of the soft keyboard changes after it has been hidden, then presented for the second time. I can't find a reason for this and there doesn't seem to be anything in the hide-delegate that changes its value. What causes this? I have worked around the problem by storing the height then using it the second time, but I would like to know the cause of this issue.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect visibleRect = self.view.frame;
if (_storedKeyboardHeight.size.height == 0) {
_storedKeyboardHeight.size.height = keyboardSize.height;
}
visibleRect.size.height = _storedKeyboardHeight.size.height;
visibleRect.origin.y = self.view.height - visibleRect.size.height;
CGRect rectOfCellInTableView = [self.loginTableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
//This changes the second time
NSLog(#"🦁 %f", keyboardSize.height);
//so I store the original value here
NSLog(#"🦁 %#", CGRectCreateDictionaryRepresentation(_storedKeyboardHeight));
if ((rectOfCellInTableView.origin.y + rectOfCellInTableView.size.height) > visibleRect.origin.y){
CGPoint scrollPoint = CGPointMake(0.0, (rectOfCellInTableView.origin.y + rectOfCellInTableView.size.height) - visibleRect.origin.y + 50);
[self.loginTableView setContentOffset:scrollPoint animated:YES];
}
}
First time the height is 291, second time it's 233.
The problem is that you are examining the wrong frame:
UIKeyboardFrameBeginUserInfoKey
When the keyboard is shown, what its frame height is at the beginning of the showing process is of no interest to you. What you want to know is the frame at the end of the showing process:
UIKeyboardFrameEndUserInfoKey
Also, it looks like you are getting notified of the wrong thing. You have not shown what notification you are registered for, but the name of your method, keyboardWasShown, suggests that your are getting notified when the keyboard did show. That's too late; this notification is almost never of any interest. You want to know when the keyboard will show.
Testing my app on iOS 11 beta 7 - it seems like the keyboard doesn't push up the content if my UIViewController.
The code looks like this (working since iOS7):
- (void)handleNotification:(NSNotification*)notification {
if (notification.name == UIKeyboardWillShowNotification) {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
nextButtonALBottomDistance.constant = keyboardSize.height + initialPhoneBottomDistance;
codeBottomViewALBottomDistance.constant = keyboardSize.height + initialCodeBottomDistance;
double animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
else if (notification.name == UIKeyboardWillHideNotification) {
nextButtonALBottomDistance.constant = initialPhoneBottomDistance;
codeBottomViewALBottomDistance.constant = initialCodeBottomDistance;
double animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
}
Interesting enough - when I press the home button (minimizing the app) and reopening it (without killing it) - the layout is fixed.
It seems like an iOS 11 beta bug, but I couldn't find any reference to it so far.
Happy to know if someone else is having this issue.
Use UIKeyboardFrameEndUserInfoKey because that key is for the NSValue object containing a CGRect that identifies an end frame of the keyboard in screen coordinates. Do not use UIKeyboardFrameBeginUserInfoKey.
If you are using UIKeyboardFrameBeginUserInfoKey key for getting keyboard height, replace it with UIKeyboardFrameEndUserInfoKey to get the correct keyboard height.
In iOS 11, height value of the frame for UIKeyboardFrameBeginUserInfoKey key is 0 because it is a start frame. To get the actual height we need the end frame, and end frame is returned by UIKeyboardFrameEndUserInfoKey.
Please refer Managing the Keyboard documentation:
UIKeyboardFrameBeginUserInfoKey The
key for an NSValue object containing a
CGRect that identifies the start frame
of the keyboard in screen coordinates.
These coordinates do not take into
account any rotation factors applied
to the window’s contents as a result
of interface orientation changes.
Thus, you may need to convert the
rectangle to window coordinates (using
the convertRect:fromWindow: method) or
to view coordinates (using the
convertRect:fromView: method) before
using it.
UIKeyboardFrameEndUserInfoKey The key
for an NSValue object containing a
CGRect that identifies the end frame
of the keyboard in screen coordinates.
These coordinates do not take into
account any rotation factors applied
to the window’s contents as a result
of interface orientation changes.
Thus, you may need to convert the
rectangle to window coordinates (using
the convertRect:fromWindow: method) or
to view coordinates (using the
convertRect:fromView: method) before
using it.
I ran into this non-movement issue as well. I suspect that the beginning & end frame were always incorrect, in that they were the same or nearly the same, but was fixed recently in iOS 11 and as such broke a lot of code that didn't truly understand the different between these two frames.
Based on the information here
https://stackoverflow.com/a/14326257/5282052
Begin is what the keyboard starts off looking like, which most won't want.
End is the result of what the keyboard will look like, which most only are concerned with.
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
Does indeed resolve my issue with a ZERO movement of the scrollview.
I am developing a chat app which has UITableView and a UIView containing a UITextField and a UIButton in it. I am using the following code to move the UIView up when keyboard appears.
(void)keyboardWillShow:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.2f animations:^{
CGRect frame = self.inputView.frame;
UIInterfaceOrientation orientation = self.interfaceOrientation;
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
frame.origin.y -= kbSize.width;
else
frame.origin.y -= kbSize.height;
self.inputView.frame = frame;
;
}];
}
This code is working fine until iOS 7, but in iOS 8 UIView is not displaying above the keyboard.
Can anyone please suggest what could be the possible issue, or is there anything that has changed in iOS 8?
Your code seems to be correct but i will prefer using UIKeyboardDidChangeFrameNotification or UIKeyboardWillChangeFrameNotification because these will tell you the change in keyboard frame when predictive text bar gets up or down when keyboard is in view.
In your ViewDidLoad add this
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardFrameDidChange:)
name:UIKeyboardDidChangeFrameNotification object:nil];
and then paste this method in your ViewController
-(void)keyboardFrameDidChange:(NSNotification*)notification{
NSDictionary* info = [notification userInfo];
CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
[yourView setFrame:CGRectMake(0, kKeyBoardFrame.origin.y-yourView.frame.size.height, 320, yourView.frame.size.height)];
}
This will handle all your keyboard cases like when its up or down or change in its frame with predictive text bar
and also remove observer when you are leaving your view
The accepted Answer is almost right. To match your view's animation to that of the keyboard you want to use the UIKeyboardWillChangeFrameNotification rather than the UIKeyboardDidChangeFrameNotification. That way the animations you kick off will precisely match that of the keyboard. Here's some code to do the entire thing. I use the animation of the keyboard to drive the animation of my autolayout constraint constants, but you can easily adapt this to animate an entire view frame. (Note, we have to use the old school style animations to hook into the UIKeyboardCurveInfoKey which provides an animation curve exactly matching the keyboard animation.
In viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardFrameDidChange:)
name:UIKeyboardWillChangeFrameNotification
object:nil];
In ViewController:
- (void)keyboardFrameDidChange:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat height = kKeyBoardFrame.size.height;
[self.view removeConstraints:self.verticalButtonConstraints];
NSDictionary *metrics = #{#"height" : #(height)};
NSDictionary *views = #{#"nextButton" : self.nextButton};
self.verticalButtonConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V: [nextButton(52)]-(height)-|" options:0 metrics:metrics views:views];
[self.view addConstraints:self.verticalButtonConstraints];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.view layoutIfNeeded];
[UIView commitAnimations];
}
I just ran into this and made a discovery I thought I would share. In iOS 8 layout passes for the sub views of the main view will be done whenever the keyboard is about to appear or about to go away. These passes do not get done on iOS 7. So if you try to animate a sub view of the main view in keyBoardWillShow or keyboardWillChangeFrame the animation will get undone by the layout pass and your sub views that you tried to animate will move back to their original position. That is why keyboardDidChangeFrame works to animate the subviews and keyboardWillChangeFrame does not.
Something odd I noted as well is the timing of when these calls are made. It seems the first time that the keyboard appears after the app is launched, the call to keyboardDidChangeFrame happens too late to be able to animate with the keyboard so they slide up together, but on second and subsequent times the keyboard shows, the call to keyboardDidChangeFrame happens sooner and it seems you can actually animate the views along with the keyboard.
I must note that I am using C# and Xamarin as my development platform for iOS, so this may be different when using Swift or Obj-C.
You can use an accessoryView, which will attach itself to the top of the keyboard. Alternatively, if you want more power over customization, you can use notifications as explained by #pankaj_wadwha to fetch the frame information. Bonus: you can also get the animation information (such as speed) so your view moves alongside the keyboard perfectly.
I have looked at a number of posts here on scrolling and unhiding a UITextField and believed that the same code should work for a UITextView, but that seems not to be the case. The first issue I encountered was that the sample app I have is an iPad app supporting landscape orientation only. The keyboard size returned from the notification had the height and width of the keyboard reversed.
Next, while I can get the scrollview to scroll the textview, it does not reveal all of it and in fact the amount of the textview that is shown is dependent on where I tap in the textview. It is more like it is scrolling to where the cursor will be which is not what I want.
Here is the code I am using. It was taken from an example, the only real change is that a UITextView is used instead of a UITextField. If the only thing I do is to replace the textview with a textfield it works fine.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.width, 0.0);
_myscrollview.contentInset = contentInsets;
_myscrollview.scrollIndicatorInsets = contentInsets;
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.width;
DebugLog(#"textview = %#", _textview);
if (!CGRectContainsPoint(aRect, _textview.frame.origin) ) {
CGPoint scrollPoint = CGPointMake(0.0, _textview.frame.origin.y-kbSize.width);
[_myscrollview setContentOffset:scrollPoint animated:YES];
}
}
If you are just wanting to scroll to the top of your UITextView you can do that by
[textview scrollRectToVisible:CGRectMake(0,0,1,1) animated:YES];
Try messing with the below method. Perhaps set it to the height of the textView. Can you post a screenshot of the issue?
- (void)textViewDidChangeSelection:(UITextView *)textView
{
[textView setSelectedRange:NSMakeRange(0, 0)];
}
Apple has provided the correct method here (check the Listing 4-1). It works for both UITextField and UITextView. We do not need to edit the range or anything else. It should be the scrollview that needs handling. The one marked as 'Answered' may work, but we better follow the creator's method!
Is there a way to detect if an external (bluetooth or usb) keyboard is connected to the iPad?
An indirect and SDK-safe way is to make a text field a first responder. If the external keyboard is present, the UIKeyboardWillShowNotification local notification shall not be posted.
Update: This is no longer true since iOS 9, however you may use the keyboard dimensions to determine if a hardware or software keyboard is involved. See How to reliably detect if an external keyboard is connected on iOS 9? for details.
You can listen to the "GSEventHardwareKeyboardAttached" (kGSEventHardwareKeyboardAvailabilityChangedNotification) Darwin notification, but this is a private API, so it's possible your app will get rejected if you use this. To check if the external hardware is present, use the private GSEventIsHardwareKeyboardAttached() function.
UIKit listens to this and sets the UIKeyboardImpl.isInHardwareKeyboardMode property accordingly, but again this is private API.
There is another level to this.
If you don't have an inputAccessoryView, you won't get the notification as the above explanations point out.
However, if you have set up an inputAccessoryView for the text view, then you will still receive a UIKeyboard notification when the external kbd is present -- the logic being that you will need to animate your view into the right location so you need the animation information contained in the notification.
Fortunately, there is enough information in the event to figure out whether the kbd will be presented, though it's still a little involved.
If we examine the notification dictionary we see this information:
UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, 1024}, {768, 308}}
UIKeyboardFrameEndUserInfoKey = NSRect: {{0, 980}, {768, 308}}
That was in Portrait; if we rotate the device to PortraitUpsideDown we get:
UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, -308}, {768, 308}}
UIKeyboardFrameEndUserInfoKey = NSRect: {{0, -264}, {768, 308}}
Similarly in LandscapeLeft and LandscapeRight we get different start and end locations.
Hmm... what do these numbers mean? You can see that the kbd is offscreen to start, but it does move a little. To make things worse, depending on the device orientation, the kbd locations are different.
However, we do have enough information to figure out what's going on:
The kbd moves from just offscreen at the physical bottom of the device to the same height as the inputAccessoryView (but obscured by it)
So in the Portrait case it moves from 1024 to 980 -- we must have an inputAccessoryView with a height of 44, which is indeed the case.
So in Portrait if the end y + the inputAccessoryView height == screen height, then the kbd is not visible. You need to handle the other rotations, but that's the idea.
Building on #user721239 the if condition determines if the bottom of the keyboard is out of the the frame of self.view. "convertRect" normalizes the frame for any orientation.
- (void)keyboardWillShow:(NSNotification *)notification {
keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil]; // convert orientation
keyboardSize = keyboardFrame.size;
//NSLog(#"keyboardFrame.origin.y = %f", keyboardFrame.origin.y);
//NSLog(#"keyboardFrame.size.height = %f", keyboardFrame.size.height);
BOOL hardwareKeyboardPresent = FALSE;;
if ((keyboardFrame.origin.y + keyboardFrame.size.height) > (self.view.frame.size.height+self.navigationController.navigationBar.frame.size.height)) {
hardwareKeyboardPresent = TRUE;
}
//NSLog(#"bottomOfKeyboard = %f", bottomOfKeyboard);
//NSLog(#"self.view.frame.size.height = %f", self.view.frame.size.height);
Even using an inputAccessoryView on your UITextView instance set to an instance of a UIView with frame CGRectZero works to get delivery of the keyboard notifications working with a hardware keyboard.
This is the code I use to get the height from the keyboard userInfo in UIKeyboardWillShowNotification. Works if with both physical and virtual keyboards.
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect = [aValue CGRectValue];
CGFloat deviceHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat deviceWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat newKeyboardHeight;
if (interfaceOrientation == UIInterfaceOrientationPortrait)
newKeyboardHeight = deviceHeight - keyboardRect.origin.y;
else if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
newKeyboardHeight = keyboardRect.size.height + keyboardRect.origin.y;
else if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
newKeyboardHeight = deviceWidth - keyboardRect.origin.x;
else
newKeyboardHeight = keyboardRect.size.width + keyboardRect.origin.x;
Based upon this thread, I've assembled two static methods that I can easily call from keyboard notification methods to handle properly resizing views (usually UIScrollViews) when a keyboard appears, regardless of type (software vs hardware):
+ (void)keyboardWillShowHide:(NSNotification *)notification
inView:(UIView *)view
adjustView:(UIView *)viewToAdjust
{
// How much should we adjust the view's frame by?
CGFloat yOffset = [SMKeyboardUtil keyboardOffsetForKeyboardNotification:notification
inView:view];
CGRect viewFrame = viewToAdjust.frame;
viewFrame.size.height -= yOffset;
// Get the animation parameters being used to show the keyboard. We'll use the same animation parameters as we
// resize our view.
UIViewAnimationCurve animationCurve;
NSTimeInterval animationDuration;
[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
// Resize the view's frame to subtract/add the height of the keyboard (and any inputAccessoryView)
[UIView beginAnimations:#"animate resiz view" context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[viewToAdjust setFrame:viewFrame];
[UIView commitAnimations];
}
+ (CGFloat)keyboardOffsetForKeyboardNotification:(NSNotification *)notification
inView:(UIView *)view
{
NSAssert(notification.userInfo[UIKeyboardFrameBeginUserInfoKey], #"Invalid keyboard notification");
// Get the frame of keyboard from the notification
CGRect keyboardFrameBeginRaw = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect keyboardFrameEndRaw = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// Because the frame we get from the notification is raw screen coordinates, without accounting for device orientation,
// we need to convert the frame to be relative to our view.
CGRect keyboardFrameBegin = [view convertRect:keyboardFrameBeginRaw fromView:nil];
CGRect keyboardFrameEnd = [view convertRect:keyboardFrameEndRaw fromView:nil];
// We could examine the size of the frame, but this does not account for hardware keyboards. Instead,
// we need to need the delta between the start and end positions to determine how much to modify
// the size of our view.
return keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y;
}
As most of the methods in the previous answers have been deprecated with iOS 8 and 9 I intersect the keyboard reported frame with the current window to get the actual visible keyboard frame. Then you can just check if the height has changed.
CGRect reportedKeyboardFrameRaw = [[[notification userInfo] valueForKey: UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect reportedKeyboardFrame = [self.view.window convertRect: reportedKeyboardFrameRaw fromWindow:nil];
CGRect visibleKeyboardFrame = CGRectIntersection(reportedKeyboardFrame, self.view.window.frame);
if (reportedKeyboardFrame.size.height != visibleKeyboardFrame.size.height)
{
// External keyboard present!
}
You can use the following which also calculates the height for keyboard/toolbar height when hardware keyboard is connected. You will need to subscribe to KeyboardWillShow notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
then handle the notification like so:
- (void)keyboardWillShow:(NSNotification *)notification
{
// Information we want to determine from notification
BOOL isHardwareKB = NO;
CGFloat keyboardHeight;
// Notification info
NSDictionary* userInfo = [notification userInfo];
CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboard = [self.view convertRect:keyboardFrame fromView:self.view.window];
CGFloat height = self.view.frame.size.height;
// Determine if hardware keyboard fired this notification
if ((keyboard.origin.y + keyboard.size.height) > height) {
isHardwareKB = YES;
keyboardHeight = height - keyboard.origin.y; // toolbar height
} else {
isHardwareKB = NO;
// As this value can change depending on rotation
keyboardHeight = MIN(keyboardFrame.size.width, keyboardFrame.size.height);
}
// adjust view ui constraints ext ext depending on keyboard height
// ....
}
You can also handle KeyboardWillHide notification. This will be fire when the firstResponder for both hardware and software keyboard.
- (void)keyboardWillShow:(NSNotification *)notification
{
// Information we want to determine from notification
BOOL isHardwareKB; // this is irrelevant since it is hidden
CGFloat keyboardHeight = 0; // height is now 0
// Do any view layout logic here for keyboard height = 0
// ...
}
Also don't forget to remove observer:
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
This is an old thread, but as of iOS 14 we now have proper APIs for tracking hardware keyboards via GameController framework using GCKeyboard and GCKeyboardDidConnect/GCKeyboardDidDisconnect notifications.
You could do something like this:
import GameController
class ViewController: UIViewController {
var isHardwareKeyboardConnected: Bool
init() {
isHardwareKeyboardConnected = GCKeyboard.coalesced != nil
super.init(nibName: nil, bundle: nil)
startObservingHardwareKeyboard()
}
func startObservingHardwareKeyboard() {
NotificationCenter.default.addObserver(self, selector: #selector(hardwareKeyboardDidConnect), name: .GCKeyboardDidConnect, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(hardwareKeyboardDidDisconnect), name: .GCKeyboardDidDisconnect, object: nil)
}
#objc func hardwareKeyboardDidConnect(_ notification: Notification) {
print("[Keyboard] Hardware keyboard did connect")
isHardwareKeyboardConnected = true
}
#objc func hardwareKeyboardDidDisconnect(_ notification: Notification) {
print("[Keyboard] Hardware keyboard did disconnect")
isHardwareKeyboardConnected = false
}
}
The following code gives you the keyboard frame for all orientations whether you're using a full screen view or the detail view of a split view.
NSDictionary* info = [aNotification userInfo];
CGRect frame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardEndFrame = [self.view convertRect:frame fromView:nil]; // The raw frame values are physical device coordinate.
CGSize keyboardSize = keyboardEndFrame.size;
The keyboard frame delivered by the notification is always in terms of hardware coordinates with the origin as the upper right corner of the screen when the iOS device in normal portrait mode with the home button at the bottom. The method -convertRect:fromView changes the coordinates from the window coordinates ( = hardware) to the local view coordinates.
I found that with a Bluetooth keyboard you get one UIKeyboardDidShowNotification the first time that there's a screen rotation but none after that. Makes it harder to distinguish the docked keyboard from the undocked/split and BT keyboards.
This is not a direct answer for detecting if an external keyboard is present, but I'm doing this to detect the actual height that is needed to display the keyboard-related view(s) at the bottom of the screen.
CGRect keyboardFrame = [[[notification userInfo] objectForKey:#"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat keyboardRelatedViewsHeight = self.view.window.frame.size.height - keyboardFrame.origin.y;
For anyone looking in Xamarin.iOS
NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification);
and then add the OnKeyboardNotification method,
private void OnKeyboardNotification(NSNotification obj)
{
var window = UIApplication.SharedApplication.KeyWindow;
var view = window.RootViewController.View;
String eventName = (UIKeyboardExtensions.HardwareKeyboardConnected(obj, view)) ? "keyboard_hardware" : "keyboard_software";
}
#philosophistry's answer worked for me. The solution is less complicated on iOS 8:
CGRect keyboardRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat deviceHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat keyboardHeight = deviceHeight - keyboardRect.origin.y;
NSLog(#"actualKeyboardHeight = %f", keyboardHeight);