UITextField文本跳转iOS 9



上一个问题的链接: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]

<标题> 的决议

我发现我有另一个键盘控制器接收键盘通知并制作一些动画。这就是问题所在

根据你编辑的问题,我可以看到,当你点击键盘上的下一步按钮时:

  1. 您正在呼叫resignFirstResponder(),然后是becomeFirstResponder()。这将调用keyboardWillHide通知,然后调用keyboardWillShow通知
  2. 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() }

最新更新