xcode 为什么每次选择另一个 TextField 时都会调用 UIKeyboardWillShowNotification?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22549911/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is UIKeyboardWillShowNotification called every time another TextField is selected?
提问by onmyway133
I have a project that contains a UIScrollView
and many UITextField
inside it.
我有一个项目,其中包含一个UIScrollView
和多个UITextField
。
For the first time I select a UITextField
, UIKeyboardWillShowNotification
is called, which is fine. But whenever I select new UITextField
(THE KEYBOARD IS STILL THERE), UIKeyboardWillShowNotification
is called again !!!, which is weird.
我第一次选择一个UITextField
,UIKeyboardWillShowNotification
被调用,这很好。但是每当我选择新的UITextField
(键盘还在那里)时,UIKeyboardWillShowNotification
就会再次被调用!!!,这很奇怪。
I also set a symbolic breakpoint for [UIResponder resignFirstResponder]
and I see that it is hit before and after UIKeyboardWillShowNotification
is called !!!
我还为它设置了一个符号断点[UIResponder resignFirstResponder]
,我看到它在UIKeyboardWillShowNotification
被调用之前和之后被击中!!!
The other thing is that UIKeyboardWillHideNotification
is only called when I hit the "Done" button on the keyboard
另一件事是UIKeyboardWillHideNotification
只有当我点击键盘上的“完成”按钮时才会调用
I'm sure to not call any resignFirstResponder
, becomeFirstResponder
, endEditing
anywhere. (I mean not call wrongly)
我肯定不会在任何地方调用任何resignFirstResponder
, becomeFirstResponder
, endEditing
。(我的意思是不要打错电话)
What can cause this problem ?
什么会导致这个问题?
Here is the stacktrace
这是堆栈跟踪
回答by onmyway133
The problem is I set inputAccessoryView
for the UITextField
, and this cause UIKeyboardWillShowNotification
being called again when new UITextField
is selected
The problem is I set inputAccessoryView
for the UITextField
, and this cause UIKeyboardWillShowNotification
being called again when new UITextField
is selected
This article Working With Keyboard on iOSexplains this well
这篇文章在 iOS 上使用键盘很好地解释了这一点
Additional changes take place when we connect an external keyboard to the iPad. In this particular case, the notification behavior depends on the inputAccessoryView property of the control which was the reason for displaying the keyboard.
If inputAccessoryView is not present or its height is equal to 0 points, no keyboard notifications are sent. My guess is that this is because in this case, no visual changes take place in application. Otherwise, all notifications behave as expected – which means they are being sent as in the majority of cases when the keyboard is displayed or hidden in a normal (not undocked or split) state.
当我们将外部键盘连接到 iPad 时,会发生其他变化。在这种特殊情况下,通知行为取决于控件的 inputAccessoryView 属性,这是显示键盘的原因。
如果 inputAccessoryView 不存在或其高度等于 0 点,则不会发送键盘通知。我的猜测是,这是因为在这种情况下,应用程序中没有发生任何视觉变化。否则,所有通知的行为都符合预期——这意味着它们在大多数情况下都是在键盘以正常(非停靠或拆分)状态显示或隐藏的情况下发送的。
Whenever new UITextField
is selected, the OS needs to compute the frame for the keyboard again, and the following notifications are posted
Whenever new UITextField
is selected, the OS needs to compute the frame for the keyboard again, and the following notifications are posted
UIKeyboardWillChangeFrameNotification
UIKeyboardWillShowNotification
UIKeyboardDidChangeFrameNotification
UIKeyboardDidShowNotification
The same applies for when the TextField loses its first responder status
这同样适用于 TextField 失去其第一响应者状态时
Note that using the sameView for inputAccessoryView
will cause UIKeyboardWillShowNotification
only called once
请注意,使用相同的View forinputAccessoryView
将导致UIKeyboardWillShowNotification
仅调用一次
回答by paulvs
To workaround the problem, I used the following code to cancel the UIKeyboardWillShowNotification
callback if the keyboard's frame is not changing.
为了解决这个问题,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
}
...
}
For Swift 3/4:
对于 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
...
}
回答by matt
In general I find that many things can cause spurious UIKeyboardWillShow
and UIKeyboardWillHide
notifications. My solution is to use a property to track whether the keyboard is already showing:
总的来说,我发现很多事情都会导致虚假UIKeyboardWillShow
和UIKeyboardWillHide
通知。我的解决方案是使用一个属性来跟踪键盘是否已经显示:
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
}
Those guards block exactly the spurious notifications, and all is well after that. And the keyboardShowing
property can be useful for other reasons, so that it is something worth tracking anyway.
那些守卫准确地阻止了虚假通知,之后一切都会好起来的。并且该keyboardShowing
属性可能因其他原因而有用,因此无论如何它都值得跟踪。
回答by Balram Tiwari
The best approach is to Add notification & remove it once your purpose is solve.
最好的方法是添加通知并在您的目的解决后将其删除。
like this .
像这样 。
- (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];
}
Now write your code for movement of views & textField in keyboardWillShow
& revert them back to position in keyboardWillHide
methods.
现在编写用于移动视图和 textField 的代码keyboardWillShow
并将它们恢复到keyboardWillHide
方法中的位置。
Also remove the observers
也删除观察者
- (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];
}
You can also resign the responder when you press return
key.
您也可以按return
键退出响应者。
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[_txtFieldEmail resignFirstResponder];
[_txtFieldPassword resignFirstResponder];
return YES;
}
That should solve your issue.
那应该可以解决您的问题。
回答by weienw
For those not using inputAccessoryView but are still having problems, it may be due to using sensitive (password) fields. See this Stack Overflow post and answer: keyboardWillShow in IOS8 with UIKeyboardWillShowNotification
对于那些不使用 inputAccessoryView 但仍有问题的人,可能是由于使用了敏感(密码)字段。请参阅此堆栈溢出帖子并回答:带有 UIKeyboardWillShowNotification 的 IOS8 中的 keyboardWillShow
回答by Recycled Steel
I have struggled with this, after half a day of searching around and experimenting I think this is the shortest and most reliable code. It is a mix of a number of answers most of which I forget where I found (parts of which are mentioned here).
我一直在努力解决这个问题,经过半天的搜索和试验,我认为这是最短和最可靠的代码。它混合了许多答案,其中大部分我忘记了我在哪里找到的(其中部分在此处提到)。
My problem was a WKWebView which (when the user changed fields) would spawn a load of WillShow, WillHide, etc notifications. Plus I had problem with the external keyboard which still has the onscreen touch bar thing.
我的问题是一个 WKWebView,它(当用户更改字段时)会产生大量 WillShow、WillHide 等通知。另外,我对外部键盘有问题,它仍然有屏幕触摸栏的东西。
This solution uses the same animation code to "Open" and "Close" the keyboard, it will also cope with external keyboard being attached and custom keyboard views.
该解决方案使用相同的动画代码来“打开”和“关闭”键盘,它还可以处理附加的外部键盘和自定义键盘视图。
First register for the UIKeyboardWillChangeFrameNotification.
首先注册 UIKeyboardWillChangeFrameNotification。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
Then you simply need to map the changes to your view in however you do it (change a hight or bottom constraint constant).
然后,您只需将更改映射到您的视图中(更改高度或底部约束常量)。
- (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];
}
The Animation to Option conversion seems to work (I can only find examples of it being used and not how/why), however, I am not convinced it will stay that way so it may be wise to use a "stock" option. It seems that the Keyboard uses some none specified Animation.
动画到选项的转换似乎有效(我只能找到它被使用的例子,而不是如何/为什么),但是,我不相信它会保持这种状态,所以使用“股票”选项可能是明智的。似乎键盘使用了一些未指定的动画。