UIKeyboardDidShowNotification called multiple times, and sometimes with incorrect keyboard dimensions

爱⌒轻易说出口 提交于 2019-12-03 16:14:12

问题


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];
}

回答1:


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.




回答2:


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.




回答3:


In my case, I register for my keyboard notifications in ViewWillAppear and unregister in ViewWillDisappear too. But, It will cause the UIKeyboardDidShowNotification handler be fired multiple times. Seem like the unregister method do not work, so, every time the view appears, the counts of Observer for UIKeyboardDidShowNotification plus 1. Then, you touch inside UITextField, multiple Observer be notified, handler be fired again and again.

So, you must register for keyboard notifications in ViewDidLoad and don't unregister. Just like the Apple mentioned in this page,

// Call this method somewhere in your view controller setup code.

I think the 'setup' means ViewDidLoad.And In the Handling the keyboard notifications code list,no ViewWillDisappear.

Here's my handler for keyboard notify, and it work.

   func keyboardWillShow(notification: NSNotification) {
    let userInfo = notification.userInfo!
    let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
    debugPrint("Before",NotifyView.frame)
    NotifyView.frame.offsetInPlace(dx: 0, dy: -keyboardHeight)
    debugPrint("After",NotifyView.frame)
}
func keyboardWillHide(notification: NSNotification) {//Do Nothing
}



回答4:


- (void)keyboardDidAppear:(NSNotification *)note {
    CGSize keyboardSize = [note.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0);
    textView.contentInset = contentInsets;
    textView.scrollIndicatorInsets = contentInsets;
}

- (void)keyboardWillBeHidden:(NSNotification *)note {
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    textView.contentInset = contentInsets;
    textView.scrollIndicatorInsets = contentInsets;
}

The solution is from Apple's official solution here like 曹 said.



来源:https://stackoverflow.com/questions/27614880/uikeyboarddidshownotification-called-multiple-times-and-sometimes-with-incorrec

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!