簡體   English   中英

為什么每次選擇另一個TextField時都會調用UIKeyboardWillShowNotification?

[英]Why is UIKeyboardWillShowNotification called every time another TextField is selected?

我有一個項目,其中包含一個UIScrollView和許多UITextField

我第一次選擇UITextFieldUIKeyboardWillShowNotification ,這很好。 但每當我選擇新的UITextField (鍵盤UIKeyboardWillShowNotification那里)時,再次調用UIKeyboardWillShowNotification !!!,這很奇怪。

我還設置了一個象征性的斷點[UIResponder resignFirstResponder]我看到它之前擊中后UIKeyboardWillShowNotification被稱為!

另一件事是只有當我按下鍵盤上的“完成”按鈕時才會調用UIKeyboardWillHideNotification

我肯定不會在任何地方調用任何resignFirstResponderbecomeFirstResponderendEditing (我的意思是不要錯誤地打電話)

什么可能導致這個問題?

這是堆棧跟蹤 在此輸入圖像描述

問題是我為UITextField設置了inputAccessoryView ,這會導致在選擇新的UITextField時再次調用UIKeyboardWillShowNotification

這篇文章在iOS上使用鍵盤解釋了這一點

當我們將外部鍵盤連接到iPad時,會發生其他更改。 在這種特殊情況下,通知行為取決於控件的inputAccessoryView屬性,這是顯示鍵盤的原因。

如果inputAccessoryView不存在或其高度等於0磅,則不會發送鍵盤通知。 我的猜測是,這是因為在這種情況下,應用程序中不會發生視覺變化。 否則,所有通知都按預期運行 - 這意味着在鍵盤顯示或隱藏在正常(未取消停靠或拆分)狀態的大多數情況下,它們將被發送。

每當選擇新的UITextField ,操作系統需要再次計算鍵盤的幀,並發布以下通知

UIKeyboardWillChangeFrameNotification
UIKeyboardWillShowNotification
UIKeyboardDidChangeFrameNotification
UIKeyboardDidShowNotification

當TextField失去其第一個響應者狀態時,這同樣適用

請注意,對inputAccessoryView使用相同的 View將導致UIKeyboardWillShowNotification僅調用一次

要解決此問題,我使用以下代碼取消UIKeyboardWillShowNotification回調,如果鍵盤的框架沒有更改。

func keyboardWillShow(notification: NSNotification) {

    let beginFrame = notification.userInfo![UIKeyboardFrameBeginUserInfoKey]!.CGRectValue()
    let endFrame = notification.userInfo![UIKeyboardFrameEndUserInfoKey]!.CGRectValue()

    // Return early if the keyboard's frame isn't changing.
    guard CGRectEqualToRect(beginFrame, endFrame) == false else {
        return
    }

    ...
}

對於Swift 3/4:

func keyboardWillShow(notification: Notification) {

    let userInfo = notification.userInfo!
    let beginFrameValue = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)!
    let beginFrame = beginFrameValue.cgRectValue
    let endFrameValue = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)!
    let endFrame = endFrameValue.cgRectValue

    if beginFrame.equalTo(endFrame) {
        return
    }

    // Do something with 'will show' event
    ...
}

一般來說,我發現很多東西都可能導致虛假的UIKeyboardWillShowUIKeyboardWillHide通知。 我的解決方案是使用屬性來跟蹤鍵盤是否已經顯示:

func keyboardShow(_ n:Notification) {
    if self.keyboardShowing {
        return
    }
    self.keyboardShowing = true
    // ... other stuff
}

func keyboardHide(_ n:Notification) {
    if !self.keyboardShowing {
        return
    }
    self.keyboardShowing = false
    // ... other stuff
}

那些警衛完全阻止虛假通知,之后一切都很好。 keyboardShowing屬性可能因其他原因而有用,因此無論如何都值得跟蹤。

最好的方法是添加通知並在您的目的解決后將其刪除。

像這樣 。

- (void)viewWillAppear:(BOOL)animated
{
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

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

現在在keyboardWillShow編寫用於移動視圖和textField的代碼,並將它們恢復到keyboardWillHide方法中的位置。

同時刪除觀察者

- (void)viewWillDisappear:(BOOL)animated
{
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:UIKeyboardWillShowNotification
                                              object:nil];

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

您還可以在按return鍵時退出響應者。

-(BOOL)textFieldShouldReturn:(UITextField *)textField {

    [_txtFieldEmail resignFirstResponder];
    [_txtFieldPassword resignFirstResponder];
    return YES;
}

這應該可以解決你的問題。

對於那些不使用inputAccessoryView但仍有問題的人,可能是由於使用了敏感(密碼)字段。 通過UIKeyboardWillShowNotification查看此Stack Overflow帖子並回答: IOS8中的keyboardWillShow

經過半天的搜索和實驗,我一直在努力解決這個問題,我認為這是最短,最可靠的代碼。 它是許多答案的混合,其中大多數我忘記了我發現的地方(這里提到了部分內容)。

我的問題是WKWebView(當用戶更改字段時)會產生一堆WillShow,WillHide等通知。 另外我還有外接鍵盤的問題,它仍然有屏幕觸摸條的東西。

此解決方案使用相同的動畫代碼來“打開”和“關閉”鍵盤,它還將處理附加的外部鍵盤和自定義鍵盤視圖。

首先注冊UIKeyboardWillChangeFrameNotification。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:)                                                 name:UIKeyboardWillChangeFrameNotification object:nil];

然后,您只需將更改映射到視圖中(無論您更改高度或底部約束常量)。

- (void)keyboardWillChangeFrame:(NSNotification *)notification
{
    NSDictionary *userInfo = notification.userInfo;
    CGRect keyboardEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect convertedEnd = [self.view convertRect:keyboardEnd fromView:nil];

    // Convert the Keyboard Animation to an Option, note the << 16 in the option
    UIViewAnimationCurve keyAnimation = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    // Change the Height or Y Contraint to the new value.
    self.keyboardHeightConstraint.constant = self.view.bounds.size.height - convertedEnd.origin.y;
    [UIView animateWithDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
                          delay:0.0
                        options:keyAnimation << 16
                     animations:^{
                         [self.view layoutIfNeeded];
                     } completion:nil];

}

動畫到選項轉換似乎有效(我只能找到它的使用示例,而不是如何/為什么),但是,我不相信它將保持這種方式,因此使用“庫存”選項可能是明智的。 似乎鍵盤使用了一些沒有指定的動畫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM