SWIFT: 随键盘向上移动的 UIView,初始移动后移动非常奇怪,不会返回

SWIFT: UIView which moves up with keyboard, moves very strangely after initial move, doesn't come back down

所以我有一个 UIView,当其中的文本字段正在编辑和关闭(键盘出现和隐藏)时,我想上下移动它。这是我的键盘观察器,以及 UIView 的默认约束,都在 viewDidLoad 中:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIWindow.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIWindow.keyboardWillHideNotification, object: nil)
    
    let radiusViewConstraint = NSLayoutConstraint(item: searchRadiusView!, attribute: .bottom, relatedBy: .equal, toItem: super.view, attribute: .bottom, multiplier: 1.0, constant: -30.0)

键盘功能如下:

@objc func keyboardWillShow(notification: NSNotification) {
     print("keyboardWillShow")
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {

        self.searchRadiusView.center.y += (-1 * keyboardSize.height)
        
        view.constraints[18].constant += (-1 * keyboardSize.height)
        
     UIView.animate(withDuration: 0.5, animations: {

         self.view.layoutIfNeeded()

     })
    }
}

   @objc func keyboardWillHide(notification: NSNotification){
     print("keyboardWillHide")
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {

        self.searchRadiusView.center.y += 1 * keyboardSize.height
        
        view.constraints[18].constant -= (-1 * keyboardSize.height)

     UIView.animate(withDuration: 0.5, animations: {

         self.view.layoutIfNeeded()

     })
    }

}

constraints[18] 是我在 viewDidLoad 中创建的约束。当我第一次点击文本字段时,UIView 向上移动了正确的数量。然后,当我输入我的第一个字符时,它再次向上移动相同的量,现在靠近屏幕顶部。当我关闭它时,它会向下移动到之前的高度(略高于键盘的高度,现在已关闭)。下次我编辑文本时,它再次向上移动,但由于某种原因没有达到完整的 keyboard.height 数量。当我解雇时,它会下降全键盘高度。然后重复此操作,直到 UIView 从屏幕底部掉落。这个动作太奇怪了,我不知道问题出在哪里。我想要的只是让它随着键盘上下移动。任何想法如何解决这一问题?谢谢

你做错的事情太多了,我无法一一列举,所以我刚刚修复了你的项目并提出了拉取请求。将拉取请求合并到您的存储库中,您会发现它现在可以正常工作了。

仅作记录,以下是您做错的一些主要事情:

  • 您在代码中向蓝色视图添加了底部约束。但是您已经 对蓝色视图设置了 底部约束。因此,您现在有两个,其中一个的任何更改都会引起冲突。 Xcode 控制台非常清楚地告诉您这正在发生,但您忽略了它告诉您的内容。

  • 您在更改约束常量的同时还更改了蓝色视图 center。这可能不会造成任何伤害,但毫无意义。如果您使用约束来管理视图,则不能通过其 center 来管理视图的位置;他们是对立的。

  • 在您检查的显示和隐藏方法中 keyboardFrameBeginUserInfoKey。那是错误的。你想检查 keyboardFrameEndUserInfoKey。问题不在于键盘现在在哪里,而是当它完成移动后在哪里。

  • 动画有误。不需要 UIView 动画;你已经在动画块中了。只要调用layoutIfNeeded,动画就会随着键盘的移动而发生。

  • 您谈论和访问约束的整个方式都是错误的。您使用了不正确的表达式 super.view(您的意思可能是 self.view)。但更重要的是,您尝试通过说 self.constraints[2] 来访问所需的约束。那种东西极其脆弱。正确的方法是保留对实际约束的引用(实例 属性)。在这种情况下,由于约束已经存在(在故事板中),该引用可以是一个出口。

综上所述,这是我对您的代码的重写;这是需要的完整代码:

class ViewController: UIViewController {

    @IBOutlet weak var sampleTextField: UITextField!
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
    var originalConstant: CGFloat = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIWindow.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIWindow.keyboardWillHideNotification, object: nil)
        self.originalConstant = bottomConstraint.constant
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        sampleTextField.endEditing(true)
    }
}

extension ViewController {
    @objc func keyboardWillShow(notification: NSNotification) {
        print("keyboardWillShow")
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            self.bottomConstraint.constant += keyboardSize.height + 5
            self.view.layoutIfNeeded()
        }
    }

    @objc func keyboardWillHide(notification: NSNotification){
        print("keyboardWillHide")
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            self.bottomConstraint.constant = self.originalConstant
            self.view.layoutIfNeeded()
        }
    }
}

综上所述,代码 仍然 错误,因为您没有考虑到收到 keyboardWillShow 通知的可能性 当键盘已经显示时。但是,我将其留给您稍后进行调查。