【发布时间】:2015-12-22 06:16:00
【问题描述】:
我知道这是应该发生的,但它给我带来了我不知道如何解决的问题。
我想在键盘显示时向上移动视图,以便我的文本字段保持可见。
我的文本字段有数字键盘。
我使用通知和keyboardWillShow/Hide在选择文本字段时向上/向下移动我的视图。
现在假设我点击一个文本字段,然后切换到另一个使用不同键盘(不是数字键盘)的应用程序。 keyboardWillShow 使用错误键盘的大小(来自另一个应用程序的键盘)调用,并且我的视图移动了错误的数量(它甚至根本不应该移动)。因此,当我回到我的应用程序时,我的视图位于错误的位置,甚至没有显示键盘,然后调用 keyboardWillHide 并将视图移回原位(不知从何而来)。但是一开始就不应该为其他应用调用keyboardWillShow。
我正在删除viewWillDisappear 上的通知,但这种情况仍然会发生……也许在为我调用viewWillDisappear 之前,其他应用程序调用了keyboardWillShow?
这是我的代码:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
for subview in self.view.subviews {
if subview.isKindOfClass(UITextField) {
let textField = subview as! UITextField
textField.addTarget(self, action: "textFieldDidReturn:", forControlEvents: UIControlEvents.EditingDidEndOnExit)
textField.addTarget(self, action: "textFieldDidBeginEditing:", forControlEvents: UIControlEvents.EditingDidBegin)
}
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func keyboardWillShow(notification: NSNotification) {
self.keyboardIsShowing = true
if let info = notification.userInfo {
self.keyboardFrame = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
self.arrangeViewOffsetFromKeyboard()
}
}
func keyboardWillHide(notification: NSNotification) {
self.keyboardIsShowing = false
self.returnViewToInitialFrame()
}
func arrangeViewOffsetFromKeyboard() {
if let textField = activeTextField {
let theApp: UIApplication = UIApplication.sharedApplication()
let windowView: UIView? = theApp.delegate!.window!
let textFieldLowerPoint = CGPoint(x: textField.frame.origin.x, y: textField.frame.origin.y + textField.frame.size.height)
let convertedTextFieldLowerPoint = textField.superview!.convertPoint(textFieldLowerPoint, toView: windowView)
let targetTextFieldLowerPoint = CGPoint(x: textField.frame.origin.x, y: self.keyboardFrame.origin.y)
let targetPointOffset = targetTextFieldLowerPoint.y - convertedTextFieldLowerPoint.y
let adjustedViewFrameCenter = CGPoint(x: self.view.center.x, y: self.view.center.y + targetPointOffset)
print(targetPointOffset) // When I change to a different app this prints the wrong value… but none of this should even get called.
if targetPointOffset < 0 {
UIView.animateWithDuration(0.3, animations: {
self.view.center = adjustedViewFrameCenter
})
}
}
}
func returnViewToInitialFrame() {
let initialViewRect = CGRect(x: 0.0, y: 0.0, width: self.view.frame.size.width, height: self.view.frame.size.height)
if !CGRectEqualToRect(initialViewRect, self.view.frame) {
UIView.animateWithDuration(0.2, animations: {
self.view.frame = initialViewRect
})
}
}
编辑:正如@JasonNam 在他的回答中指出的那样,切换应用程序时不会调用 viewWillDisappear,因此我必须添加一个 applicationWillResignActive 通知来删除键盘通知,并添加一个 applicationDidBecomeActive 通知来添加它们。
编辑 2:@sahara108 的解决方案看起来更干净,我看不出有任何缺点。在keyboardWillShow中做任何事情之前,我只需要检查UIApplication.sharedApplication().applicationState == .Active。
【问题讨论】:
-
代码中的一个大问题。您将
self添加为通知观察者,但您尝试删除self.view。您需要删除self。 -
糟糕,我最初是删除
self,但我注意到了这个问题并开始尝试各种疯狂的事情,包括从self.view而不是self中删除观察者,然后我忘记了当我在这里发布代码时,将那部分改回来。不过,问题仍然存在。环顾四周,我发现这显然应该发生......但我不希望它发生,我不知道该怎么做。
标签: ios swift nsnotificationcenter