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
通知的可能性 当键盘已经显示时。但是,我将其留给您稍后进行调查。
所以我有一个 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
通知的可能性 当键盘已经显示时。但是,我将其留给您稍后进行调查。