Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIKeyboardDidShowNotification called multiple times, and sometimes with incorrect keyboard dimensions

I am trying to move a UITextView above the keyboard whenever the keyboard appears/changes. Let's say I have the English keyboard displaying and then switch directly to the Chinese keyboard (which is taller than the standard English keyboard). In this scenario my text view always appears too high (to the naked eye, it looks like the text view is incorrectly offset by the size of the Chinese keyboard "input accessory view". I'd post an image but lack the reputation to do so :) ). I am adjusting my text view position when my app receives a UIKeyboardDidShowNotification (using UIKeyboardFrameEndUserInfoKey to get the height), and after some investigation UIKeyboardDidShowNotification is called multiple times, oftentimes with the incorrect keyboard dimensions (I've NSLogged the userInfo dictionary). I register for my keyboard notifications in ViewWillAppear and unregister in ViewWillDisappear. I am unable to determine what might be causing this notification to fire multiple times; my understanding is that this notification should only be fired one time, right after the keyboard finishes displaying. An additional note: I've NSLogged 'self' in the method that responds to UIKeyboardDidShowNotification and it is in fact always the same View Controller Object.

Even with this notification firing multiple times, however, I still do not understand why the keyboard height would be different for some of these notifications. One of the notifications always has the correct height, but when it is not the last notification fired the text view ends up in the wrong spot. Any insight on how to further troubleshoot would be much appreciated!

EDIT: The more I test the more it seems to be a problem with the Chinese keyboard specifically. Whenever I switch the keyboard from english to chinese I get three UIKeyboardWillShowNotifications:

2014-12-24 22:49:29.385 Example[1055:421943] info dictionary: {
UIKeyboardAnimationCurveUserInfoKey = 0;
UIKeyboardAnimationDurationUserInfoKey = 0;
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 252}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 460}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 442}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 352}, {320, 216}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 316}, {320, 252}}";
}
2014-12-24 22:49:29.408 Example[1055:421943] info dictionary: {
UIKeyboardAnimationCurveUserInfoKey = 0;
UIKeyboardAnimationDurationUserInfoKey = 0;
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 442}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 460}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 316}, {320, 252}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 352}, {320, 216}}";
}
2014-12-24 22:49:29.420 Example[1055:421943] info dictionary: {
UIKeyboardAnimationCurveUserInfoKey = 0;
UIKeyboardAnimationDurationUserInfoKey = 0;
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 288}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 442}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 424}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 316}, {320, 252}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 280}, {320, 288}}";
}

The first one has the correct end height: 252. However, the next two are incorrect at 216 and 288. This happens reliably.

Here are a couple of snippets to demonstrate how I am managing subscriptions to notifications:

-(void)viewWillAppear:(BOOL)animated {

       [super viewWillAppear:animated];


       [self registerForKeyboardNotifications];


}

-(void)viewWillDisappear:(BOOL)animated {
       [super viewWillDisappear:animated];

       [[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:UIKeyboardWillHideNotification
                                                object:nil];
       [[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:UIKeyboardDidShowNotification
                                                object:nil];

}

- (void)registerForKeyboardNotifications {



      [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardDidHide:)
                                             name:UIKeyboardWillHideNotification object:nil];

      [[NSNotificationCenter defaultCenter] addObserver:self      
                                         selector:@selector(keyboardDidShow:)                                       
                                             name:UIKeyboardDidShowNotification object:nil];
}
like image 365
Benny B Avatar asked Dec 23 '14 05:12

Benny B


2 Answers

If you're using the Cmd+K shortcut on the simulator to show/hide the keyboard, it may get called multiple times since that doesn't resign the textfield as the first responder.

If you instead use the keyboard's Return button then it will do the right thing and resign it.

like image 151
iwasrobbed Avatar answered Nov 08 '22 14:11

iwasrobbed


The primary reason is that the your notification is invoked multiple times. For example, in swift, if you had the NSNotificationCenter.defaultCenter().addObserver(xx"keyboardWillShow"xx) inside viewWillAppear method and if you are going back and forth between the view then it will result in having multiple observer of the same "keyboardWillShow". Instead you should consider moving the addObserver call to "viewDidLoad()" method. Alternatively you can register/deregister observer when the view appears/disappears.

like image 31
Big D Avatar answered Nov 08 '22 12:11

Big D