上一个问题的链接:UITextField文本跳转
简要:我有ViewController
和两个UITextField
元素。当loginField为firstResponder时,在
self.passwordField.becomeFirstResponder()
登录字段中的文本跳转到左上角并返回。更奇怪的是:这个故障只会第一次重现,然后你需要重新创建ViewController
来观察这个行为
这里是故障的视频http://tinypic.com/player.php?v=6nsemw%3E&s=8#.VgVb3cuqpHx
我最终得到了这个(不适用于iOS 9):
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField === self.loginField {
self.loginField.resignFirstResponder()
// Shitty workaround. Hi, Apple!
self.loginField.setNeedsLayout()
self.loginField.layoutIfNeeded()
self.passwordField.becomeFirstResponder()
return false
}
return true
}
有人被这个bug卡住了吗?有什么建议吗?
键盘通知处理程序
我的主视图是UIScrollView,我将底部空间改为superview,这样即使键盘显示,用户也可以滚动所有内容
func keyboardWillShow(notification : NSNotification) {
let keyboardInfo = notification.userInfo!
let keyboardFrame = keyboardInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue
let animDuration = keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue!
UIView.animateWithDuration(animDuration, animations: {
self.scrollViewBottom.constant = keyboardFrame.height
self.view.layoutIfNeeded()
let offsetY = CGRectGetMaxY(self.loginButton.frame) + 10 - self.scrollView.frame.height
if offsetY > 0 {
self.scrollView.contentOffset = CGPointMake(0, offsetY)
}
})
}
func keyboardWillHide(notification : NSNotification) {
self.scrollViewBottom.constant = 0
self.view.layoutIfNeeded()
}
我发现iOS7、8和9的键盘通知非常不同。在ios9中,通知会在改变firstResponder时发送,即使键盘不会显示/隐藏。此外,当我改变firstResponder与点击textField(不是点击键盘上的下一步,这是由我的代码处理),只有KeyboardWillShow通知,没有KeyboardWillHide。至于我,userInfo有一些垃圾帧值,这是使用下一个按钮改变第一响应者时的日志(工作正常,没有故障):
2015-10-07 12:54:13.870[UIKeyboardFrameBeginUserInfoKey: NSRect: {{0,352}, {320,216}},]UIKeyboardCenterBeginUserInfoKey: npoint: {160, 460};UIKeyboardFrameEndUserInfoKey: NSRect: {{0,568}, {320,216}},UIKeyboardCenterEndUserInfoKey: npoint: {160,676};UIKeyboardAnimationDurationUserInfoKey: 0.25,UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect;{{0,0}, {320,216}}, UIKeyboardAnimationCurveUserInfoKey: 7]2015-10-07 12:54:13.896[UIKeyboardFrameBeginUserInfoKey: NSRect: {{0,352}, {320,216}},]UIKeyboardCenterBeginUserInfoKey: npoint: {160, 460};UIKeyboardFrameEndUserInfoKey: NSRect: {{0,352}, {320,216}};UIKeyboardCenterEndUserInfoKey: NSPoint: {160, 460};UIKeyboardAnimationDurationUserInfoKey: 0.25,UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect;{{0,0}, {320,216}}, UIKeyboardAnimationCurveUserInfoKey: 7]
这里是日志当我点击第二个textField:
<标题> 的决议2015-10-07 12:55:13.879keyboardWillShow:[UIKeyboardFrameBeginUserInfoKey: NSRect: {{0,352}]{320, 216}}, UIKeyboardCenterBeginUserInfoKey: NSPoint: {160,, UIKeyboardFrameEndUserInfoKey: NSRect: {{0,352}, {320;{216}}, UIKeyboardCenterEndUserInfoKey: NSPoint: {160, 460},
UIKeyboardAnimationDurationUserInfoKey: 0.25,UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect;{{0,0}, {320,216}}, UIKeyboardAnimationCurveUserInfoKey: 7]
我发现我有另一个键盘控制器接收键盘通知并制作一些动画。这就是问题所在
标题>根据你编辑的问题,我可以看到,当你点击键盘上的下一步按钮时:
- 您正在呼叫
resignFirstResponder()
,然后是becomeFirstResponder()
。这将调用keyboardWillHide
通知,然后调用keyboardWillShow
通知 - 在
keyboardWillHide
你有self.view.layoutIfNeeded()
布局视图(和子视图-文本字段)没有动画。
因为这个文本字段布局是"固定的",当你在keyboardWillShow
做动画时,文本字段中的文本不再"跳"了,因为你在keyboardWillHide
做了布局。
但是当你点击另一个文本字段时,只有keyboardWillShow
被调用,布局在文本字段中不是"固定的",当你动画视图时,文本做一个"跳跃"动画。
这就是为什么当你点击键盘上的"下一步"时它不会跳起来,但当你点击另一个文本框时它会跳起来。
所以我建议改成这样:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField === self.loginField {
self.passwordField.becomeFirstResponder()
return false
}
return true
}
func keyboardWillShow(notification : NSNotification) {
let keyboardInfo = notification.userInfo!
let keyboardFrame = keyboardInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue
let animDuration = keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue!
self.loginField.layoutIfNeeded()
self.passwordField.layoutIfNeeded()
if keyboardFrame.height != self.scrollViewBottom.constant {
UIView.animateWithDuration(animDuration, animations: {
self.scrollViewBottom.constant = keyboardFrame.height
self.view.layoutIfNeeded()
let offsetY = CGRectGetMaxY(self.loginButton.frame) + 10 - self.scrollView.frame.height
if offsetY > 0 {
self.scrollView.contentOffset = CGPointMake(0, offsetY)
}
})
}
}
Tnx to haluzak:
func textFieldShouldReturn(textField: UITextField) -> Bool {
if textField === self.loginField {
self.passwordField.becomeFirstResponder()
return false
}
return true
}
func keyboardWillShow(notification : NSNotification) {
let keyboardInfo = notification.userInfo!
let keyboardFrame = keyboardInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue
let animDuration = keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue!
UIView.performWithoutAnimation({
self.loginField.layoutIfNeeded()
self.passwordField.layoutIfNeeded()
})
if keyboardFrame.height != self.scrollViewBottom.constant {
UIView.animateWithDuration(animDuration, animations: {
self.scrollViewBottom.constant = keyboardFrame.height
self.view.layoutIfNeeded()
let offsetY = CGRectGetMaxY(self.loginButton.frame) + 10 - self.scrollView.frame.height
if offsetY > 0 {
self.scrollView.contentOffset = CGPointMake(0, offsetY)
}
})
}
}
我遇到过同样的问题,当我试图改变第一响应者。对于这个问题有一个更好的解决方案。只需实现UITextField子类,并使用在地方,你的文本字段可以动画(键盘,第一响应切换等)。
@interface UITextFieldFixed : UITextField
@end
@implementation UITextFieldFixed
- (BOOL)resignFirstResponder
{
BOOL result = [super resignFirstResponder];
[self setNeedsLayout];
[self layoutIfNeeded];
return result;
}
@end
关于问题的更多信息:https://github.com/foundry/UITextFieldBug
复制并粘贴Swift3…
class UITextFieldFixed: UITextField {
override func resignFirstResponder() -> Bool {
let r = super.resignFirstResponder()
self.setNeedsLayout()
self.layoutIfNeeded()
return r
}
}
把这段代码放在你的键盘上会显示通知,在你做任何动画之前:
UIView.performWithoutAnimation({
self.yourTextField1.layoutIfNeeded()
self.yourTextField2.layoutIfNeeded()
//etc.
})
您需要编写用于停止文本跳转的简单代码。这是我的工作。
func textFieldDidEndEditing(_ textField: UITextField) {
// Workaround for the jumping text bug.
textField.resignFirstResponder()
textField.layoutIfNeeded()
}