为什么每次选择另一个TextField时都会调用UIKeyboardWillShowNotification?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么每次选择另一个TextField时都会调用UIKeyboardWillShowNotification?相关的知识,希望对你有一定的参考价值。
我有一个项目,其中包含UIScrollView
和许多UITextField
。
我第一次选择UITextField
,UIKeyboardWillShowNotification
被称为,这很好。但每当我选择新的UITextField
(键盘仍在那里)时,再次调用UIKeyboardWillShowNotification
!!!,这很奇怪。
我还为[UIResponder resignFirstResponder]
设置了一个符号断点,我看到它在UIKeyboardWillShowNotification
被调用之前和之后被击中!!!
另一件事是,当我点击键盘上的“完成”按钮时,才会调用UIKeyboardWillHideNotification
我肯定不会在任何地方打电话给任何resignFirstResponder
,becomeFirstResponder
,endEditing
。 (我的意思是不要错误地打电话)
什么可能导致这个问题?
这是堆栈跟踪
问题是我为inputAccessoryView
设置UITextField
,这导致UIKeyboardWillShowNotification
在选择新的UITextField
时再次被调用
这篇文章Working With Keyboard on iOS很好地解释了这一点
当我们将外部键盘连接到iPad时,会发生其他更改。在这种特殊情况下,通知行为取决于控件的inputAccessoryView属性,这是显示键盘的原因。
如果inputAccessoryView不存在或其高度等于0磅,则不会发送键盘通知。我的猜测是,这是因为在这种情况下,应用程序中不会发生视觉变化。否则,所有通知都按预期运行 - 这意味着在键盘显示或隐藏在正常(未取消停靠或拆分)状态的大多数情况下,它们将被发送。
每当选择新的UITextField
时,操作系统需要再次计算键盘的帧,并发布以下通知
UIKeyboardWillChangeFrameNotification
UIKeyboardWillShowNotification
UIKeyboardDidChangeFrameNotification
UIKeyboardDidShowNotification
当TextField失去其第一个响应者状态时,这同样适用
请注意,对inputAccessoryView
使用相同的视图将导致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
...
}
一般来说,我发现许多事情可能导致虚假的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
}
那些警卫完全阻止虚假通知,之后一切都很好。而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但仍有问题的人,可能是由于使用了敏感(密码)字段。请参阅此Stack Overflow帖子并回答:keyboardWillShow in IOS8 with UIKeyboardWillShowNotification
经过半天的搜索和实验,我一直在努力解决这个问题,我认为这是最短,最可靠的代码。它是许多答案的混合,其中大多数我忘记了我发现的地方(这里提到了部分内容)。
我的问题是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];
}
动画到选项转换似乎有效(我只能找到它的使用示例,而不是如何/为什么),但是,我不相信它将保持这种方式,因此使用“库存”选项可能是明智的。似乎键盘使用了一些没有指定的动画。
以上是关于为什么每次选择另一个TextField时都会调用UIKeyboardWillShowNotification?的主要内容,如果未能解决你的问题,请参考以下文章
在apache中-每次调用php文件时都会从磁盘读取它们吗?