keyboardWillShow被调用其他应用程序的键盘

问题描述 投票:6回答:7

我知道这是应该发生的事情,但它导致了我不知道如何修复的问题。

我想在键盘显示时向上移动我的视图,以便我的文本字段保持可见。

我的文本字段有数字键盘。

当选择文本字段时,我使用通知和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

ios swift nsnotificationcenter
7个回答
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()
    }
}

更新:如果你检查qazxsw poi,它会更安全,而不是检查第一个响应者


4
投票

仅限iOS 9+:

来自键盘的NSNotification包含以下内容:

UIKeyboardIsLocalUserInfoKey - 包含布尔值的NSNumber对象的键,该布尔值标识键盘是否属于当前应用程序。

在我的情况下,我也这样做(OP也可能需要):

UIApplication.shareApplication().applicationSate == .Active

这样,在应用程序之间切换时键盘不会隐藏。


1
投票

只需检查应用程序状态是否处于活动状态即可:

func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    return UIApplication.shared.applicationState == .active
}

0
投票

您认为几乎是正确的:您必须删除viewWillDisappear中的特定通知:

- (void)handleKeyboardWillShowNotification:(NSNotification *)notifaction{
    if([UIApplication sharedApplication].applicationState != UIApplicationStateActive){
        return;
    }
    //your code below...
}

0
投票

您可以在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) } 上取消注册通知并再次在UIApplicationDidEnterBackgroundNotification中注册。我不能确定这种行为是故意的,但对我来说绝对是意想不到的。

UIApplicationDidBecomeActiveNotification

0
投票

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) } 中执行任何操作之前,您可以确保视图包含第一响应者。使用像keyboardWillShow -sorry这样的UIView扩展(或类别)无法找到快速等效但你明白了 - 你可以检测到任何视图的子视图是否是第一响应者。我相信这也适用于在iOS 9上同时在前台拥有2个应用程序的情况。


0
投票

我无法使用应用程序生命周期方法,但我能够通过检查当前视图中的任何文本字段是否为firstResponder来自行解决此问题。

更新代码:

this one
© www.soinside.com 2019 - 2024. All rights reserved.