Andrew Varvel
Andrew Varvel

Reputation: 1316

UIKeyboardWillShow Notification from other apps

My app monitors changes to the keyboard to animate specific parts of the UI using UIKeyboardWillShow and UIKeyboardWillHide notifications.

The issue I am having is that when I switch from the Messages app with the keyboard shown to my app using the app switcher (in a state where the keyboard is not required), it will trigger the UIKeyboardWillShow notification and then the UIKeyboardWillHide notification which is resulting in my UI jumping up and down a bit.

Is there a way to only listen to keyboard notifications for your own app?

ViewWillAppear

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChange:", name: UIKeyboardWillChangeFrameNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

ViewWillDisappear

    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillChangeFrameNotification, object: nil)

Upvotes: 1

Views: 536

Answers (2)

Soja
Soja

Reputation: 512

I came across this problem today. What I ended up doing was adding observers to detect when the app enters and leaves background. If it enters background then remove the keyboard observer else add the keyboard observers. Something like this... I'm sure there's a better way, but this worked for me. Hope this helps.

override func viewDidLoad() {
    super.viewDidLoad()
    registerForPreviewing(with: self, sourceView: collectionView)
    addApplicationStateObservers()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    addKeyboardObservers()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeKeyboardObservers()
}

deinit {
    removeApplicationStateObservers()
    removeKeyboardObservers()
}

func applicationIsActive() {
    let delay = DispatchTime.now() + 0.1
    DispatchQueue.main.asyncAfter(deadline: delay) {
        self.addKeyboardObservers()
    }
}

// Observers 
// Application state observers were add to handle edge case scenario where if user is playing a video in expanded pip view on iPhone, if user switchs to another app with keyboard then switch back, the video will disppears. Our app removes and re-adds observer as user enter and exit the app. 

func addApplicationStateObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(applicationIsActive), name: .UIApplicationDidBecomeActive, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(removeKeyboardObservers), name: .UIApplicationDidEnterBackground, object: nil)
}

func removeApplicationStateObservers() {
    NotificationCenter.default.removeObserver(self, name: .UIApplicationDidBecomeActive, object: nil)
    NotificationCenter.default.removeObserver(self, name: .UIApplicationDidEnterBackground, object: nil)
}

func addKeyboardObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown), name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden), name: .UIKeyboardWillHide, object: nil)
}

func removeKeyboardObservers() {
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}

Upvotes: 0

Luan Nguyen
Luan Nguyen

Reputation: 395

Any code? Do you observe keyboard entire your app or only in a viewcontroller?

Whenever you don't want to listen the changes you can removeObserver

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [[NSNotificationCenter defaultCenter] removeObserver:yourClass name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:yourClass name:UIKeyboardWillHideNotification object:nil];
}

But be careful, you need to use NSNotificationCenter properly.

Upvotes: 1

Related Questions