我知道这是应该发生的事情,但它导致了我不知道如何修复的问题。
我希望在键盘显示时移动我的视图,以便我的文本字段保持可见。
我的文字字段有数字键盘。
我选择文本字段时使用通知和keyboardWillShow/Hide
向上/向下移动视图。
现在假设我点击文本字段然后切换到使用其他键盘(而不是数字小键盘)的另一个应用程序。使用错误键盘的大小调用keyboardWillShow
(来自另一个应用程序的键盘)并且我的视图移动的数量错误(它根本不应该移动)。因此,当我回到我的应用程序时,我的视图位于错误的位置,键盘甚至没有显示,然后调用keyboardWillHide
并将视图移回原位(无处不在)。但是,首先不应该为其他应用调用keyboardWillShow
。
我正在移除viewWillDisappear
上的通知,但这仍然会发生......在我的keyboardWillShow
被调用之前,其他应用可能会调用viewWillDisappear
吗?
这是我的代码:
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
。
答案 0 :(得分:9)
我建议您使用textField
方法检查keyboardWillShown
是否是第一响应者。如果不是,请忽略通知。
func keyboardWillShow(notification: NSNotification) {
if !myTextField.isFirstResponder() {
return
}
self.keyboardIsShowing = true
if let info = notification.userInfo {
self.keyboardFrame = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
self.arrangeViewOffsetFromKeyboard()
}
}
<强>更新强>
如果您选中UIApplication.shareApplication().applicationSate == .Active
答案 1 :(得分:4)
仅限iOS 9+:
来自键盘的NSNotification包含以下内容:
UIKeyboardIsLocalUserInfoKey - 包含布尔值的NSNumber对象的键,该布尔值标识键盘是否属于当前应用。
在我的情况下,我也这样做(OP也可能需要这样做):
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
return UIApplication.shared.applicationState == .active
}
这样,在应用程序之间切换时,键盘不会隐藏。
答案 2 :(得分:1)
只需检查应用状态是否有效就可以了:
- (void)handleKeyboardWillShowNotification:(NSNotification *)notifaction{
if([UIApplication sharedApplication].applicationState != UIApplicationStateActive){
return;
}
//your code below...
}
答案 3 :(得分:0)
您认为几乎是正确的:您必须删除viewWillDisappear中的特定通知:
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
notificationCenter.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
答案 4 :(得分:0)
您可以在UIApplicationDidEnterBackgroundNotification
上取消注册通知
并在UIApplicationDidBecomeActiveNotification
再次注册。我不能确定这种行为是故意的,但对我来说绝对是意想不到的事情。
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationBecomeActive", name: UIApplicationDidBecomeActiveNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationDidEnterBackground", name: UIApplicationDidEnterBackgroundNotification, object: nil)
}
func applicationBecomeActive()
{
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}
func applicationDidEnterBackground()
{
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
答案 5 :(得分:0)
在keyboardWillShow
中执行任何操作之前,您可以确保视图包含第一响应者。使用像this one -sorry这样的UIView扩展(或类别)无法找到快速等效但你明白了 - 你可以检测到任何视图的子视图是否是第一响应者。我相信这也适用于在iOS 9上同时在前台安装2个应用程序的情况。
答案 6 :(得分:0)
我无法使用“应用程序生命周期”方法,但可以通过检查当前视图中的任何文本字段是否为firstResponder来为自己解决此问题。
已更新代码:
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: UIResponder.keyboardWillShowNotification,object: nil)
@objc func keyboardWillShow(_ notification: Notification) {
if storeNameTextField.isFirstResponder || methodTextField.isFirstResponder || amountTextField.isFirstResponder || dateTextField.isFirstResponder || categoryTextField.isFirstResponder {
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
self.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight - 22, right: 0)
}
}
}