68

Is there some way to get UIKeyboard size programmatically. 216.0f height and 162.0f height in landscape.

Following seem to be deprecated. Is there some way that works without any warning in both 3.0 iPhone OS SDK and 4.0 iPhone OS SDK to do this..

CGSize keyBoardSize = [[[note userInfo]
                        objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size;
Cœur
  • 37,241
  • 25
  • 195
  • 267
Tharindu Madushanka
  • 3,241
  • 7
  • 31
  • 33
  • 2
    In 2011, Apple finally has a good introductory about keyboard handling and size: http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html. – Wayne Lo Nov 25 '11 at 13:50

4 Answers4

143

You can get the keyboard size from the userInfo dictionary using the UIKeyboardFrameBeginUserInfoKey and the UIKeyboardFrameEndUserInfoKey instead.

These two keys return a NSValue instance containing a CGRect that holds the position and size of the keyboard at both the start and end points of the keyboard's show/hide animation.

Edit:

To clarify, the userInfo dictionary comes from an NSNotification instance. It's passed to your method that you register with an observer. For example,

- (void)someMethodWhereYouSetUpYourObserver
{
    // This could be in an init method.
    [[NSNotificationCenter defaultCenter] addObserver:self 
                    selector:@selector(myNotificationMethod:) 
                    name:UIKeyboardDidShowNotification 
                    object:nil];
}

- (void)myNotificationMethod:(NSNotification*)notification
{
    NSDictionary* keyboardInfo = [notification userInfo];
    NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
}

Edit 2:

Also, please don't forget to remove yourself as an observer in your dealloc method! This is to avoid a crash that would occur when the notification center tries to notify your object after its been freed.

Rahul
  • 5,594
  • 7
  • 38
  • 92
James Bedford
  • 28,702
  • 8
  • 57
  • 64
  • 1
    Sorry to revive a zombie here, but where does the userInfo dictionary come from - what object to I call `-userInfo` on to get it? – Alex Gosselin Jul 24 '11 at 15:36
  • I think you want to take a look at this question for that problem. http://stackoverflow.com/questions/820142/how-to-target-a-specific-iphone-version – James Bedford Oct 07 '12 at 18:27
  • `keyboardFrameBeginRect` might have different origin and size values than what you would expect if, for example, the device is in landscape. To fix this, just convert the returned rect to appropriate coordinates. Supposing the observer is a view controller, add one more line of code like this: `CGRect keyboardFrameFixed = [self.view convertRect:keyboardFrameBeginRect fromView:self.view.window];` Now, `keyboardFrameFixed` will have expected values no matter device's orientation. This is useful if you want to find out, for example, keyboard's height to move things on screen accordingly. – camilomq Jul 30 '14 at 18:29
  • 3
    Dont forget to: - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } – Yevgeni Sep 28 '14 at 14:24
  • 12
    It is actually better to use UIKeyboardFrameEndUserInfoKey to determine the end height of the keyboard in the case that the user is hiding/showing the QuickType suggestions. To hide/show the QuickType suggestions you swipe up or swipe down on the suggestions located above the keyboard. The height of the keyboard will be incorrect if you use UIKeyboardFrameBeginUserInfoKey instead of UIKeyboardFrameEndUserInfoKey – Ross Barbish Dec 05 '14 at 22:21
  • As in `ARC` we don't have `- (void) dealloc` method, so you can remove the observer in `viewWillDisappear` method. – Ans Apr 07 '15 at 08:22
  • This does not seem to be working correctly with hardware keyboard. Height is incorrect. – Vlad May 26 '16 at 05:16
  • This API is only for the software keyboard as far as I'm aware..! – James Bedford May 30 '16 at 11:30
  • Is it true that the observer has to be a UIView? I cannot seem to get this to work otherwise. – galactikuh Aug 08 '16 at 14:26
52

You should use the UIKeyboardWillChangeFrameNotification instead, because some international keyboards, like the Chinese keyboard, will change frames during use. Also make sure to convert the CGRect into the proper view, for landscape use.

//some method like viewDidLoad, where you set up your observer.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];

- (void)keyboardWillChange:(NSNotification *)notification {
    CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardRect = [self.view convertRect:keyboardRect fromView:nil]; //this is it!
}
Jeffrey Sun
  • 7,789
  • 1
  • 24
  • 17
  • 3
    +1 for a great answer. Very helpful also works with 3rd party keyboards in iOS 8 – Bocaxica Sep 23 '14 at 14:32
  • 1
    I'm getting a different CGRect from `[self.view convertRect:keyboardRect fromView:nil]` on iOS 8 than I was on iOS 7... – Isaac Overacker Sep 26 '14 at 04:47
  • +1 for `UIKeyboardFrameEndUserInfoKey`! I had somehow gotten using `UIKeyboardFrameBeginUserInfoKey`, which is actually the size of the keyboard *before* the resize and was wondering why everything was messed up! – devios1 May 26 '15 at 17:49
4

Here's how I finally made works. I combined suggestions and codes from different answers. Features: dismissing keyboard, moving text fields above keyboard while editing and setting "Next" and "Done" keyboard return type.REPLACE "..." with more fields

static const CGFloat ANIMATION_DURATION = 0.4;
static const CGFloat LITTLE_SPACE = 5;
CGFloat animatedDistance;
CGSize keyboardSize;

@interface ViewController () <UITextFieldDelegate>
 @property (weak, nonatomic) IBOutlet UITextField *firstNameTXT;
  .....// some other text fields
 @property (weak, nonatomic) IBOutlet UITextField *emailTXT;
@end

@implementation ViewController
- (void)viewDidLoad{
.....
// add tap gesture to help in dismissing keyboard
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]
                                       initWithTarget:self
                                       action:@selector(tapScreen:)];// outside textfields

[self.view addGestureRecognizer:tapGesture];

// set text fields return key type to Next, last text field to Done
[self.firstNameTXT setReturnKeyType:UIReturnKeyNext];
.....
[self.emailTXT setReturnKeyType:UIReturnKeyDone];

// set text fields tags
[self.firstNameTXT setTag:0];
....// more text fields
[self.emailTXT setTag:5];

// add keyboard notification
[[NSNotificationCenter defaultCenter] addObserver:self     selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}
[[NSNotificationCenter defaultCenter] addObserver:self      selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
}

// dismiss keyboard when tap outside text fields
- (IBAction)tapScreen:(UITapGestureRecognizer *)sender {
  if([self.firstNameTXT isFirstResponder])[self.firstNameTXT resignFirstResponder];
  ...
  if([self.emailTXT isFirstResponder])[self.emailTXT  resignFirstResponder];

  }
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
   if(textField.returnKeyType==UIReturnKeyNext) {
     // find the text field with next tag
     UIView *next = [[textField superview] viewWithTag:textField.tag+1];
     [next becomeFirstResponder];
   } else if (textField.returnKeyType==UIReturnKeyDone || textField.returnKeyType==UIReturnKeyDefault) {
    [textField resignFirstResponder];
 }
return YES;
}

// Moving current text field above keyboard
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField{
   CGRect viewFrame = self.view.frame;
   CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
   CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
   CGFloat textFieldBottomLine = textFieldRect.origin.y + textFieldRect.size.height + LITTLE_SPACE;//

   CGFloat keyboardHeight = keyboardSize.height;

   BOOL isTextFieldHidden = textFieldBottomLine > (viewRect.size.height - keyboardHeight)? TRUE :FALSE;
  if (isTextFieldHidden) {
    animatedDistance = textFieldBottomLine - (viewRect.size.height - keyboardHeight) ;
    viewFrame.origin.y -= animatedDistance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
  return YES;
}

-(void) restoreViewFrameOrigionYToZero{
  CGRect viewFrame = self.view.frame;
  if (viewFrame.origin.y != 0) {
    viewFrame.origin.y = 0;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
}

-(void)keyboardDidShow:(NSNotification*)aNotification{
   NSDictionary* info = [aNotification userInfo];
   keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
 }

-(void)keyboardDidHide:(NSNotification*)aNotification{
   [self restoreViewFrameOrigionYToZero];// keyboard is dismissed, restore frame view to its  zero origin
}
@end
Kamel
  • 1,077
  • 8
  • 4
0

On swift 4

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(getInfo(notif:)), name: .UIKeyboardDidShow , object: nil)
}

and then:

@objc func getInfo(notif: NSNotification) -> Void {  
    guard let userInfo = notif.userInfo else {return}

    if let myData = userInfo["UIKeyboardFrameBeginUserInfoKey"] as? CGRect {
        print(myData.width)
        print(myData.height)
    }
}
Ennabah
  • 2,303
  • 2
  • 20
  • 39
omi5489
  • 381
  • 3
  • 8