Search This Blog

Friday, February 2, 2018

iOS Swift. Check if keyboard is visible

How we can get is keyboard is shown or hidden currently in our app?

Keyboard is shown

That is it. Simple solution, we just need to add observer for keyboard notification.
override func viewDidLoad() {
    super.viewDidLoad()
        
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardShow),
                                           name: Notification.Name.UIKeyboardWillShow, object: nil)       
}
    
@objc func handleKeyboardShow(notification: Notification) {
    print("Keyboard will show")
}
This observer only works for event when keyboard will be shown, there is another observer for event when keyboard will be hidden.

override func viewDidLoad() {
    super.viewDidLoad()
        
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardShow),
                                           name: Notification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardHide),
                                           name: Notification.Name.UIKeyboardWillHide, object: nil)
}
    
@objc func handleKeyboardShow(notification: Notification) {
    print("Keyboard will show")
}
    
@objc func handleKeyboardHide(notification: Notification) {
    print("Keyboard will hide")
}
But there is a lot more thing beside this. And I want to tell you about some of them.
For easily hide keyboard we can override this method in View Controller.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
}
Also, when we work with observers we should remove them when we don't need them anymore. It is need to be remove because we don't need to receive events when we leave current controller. In method viewDidDisappear we remove observer. And we moving adding of observers from viewDidLoad to viewDidAppear. Because when we return to current View Controller again we need observers to be worked.
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
        
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardShow),
                                           name: Notification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardHide),
                                           name: Notification.Name.UIKeyboardWillHide, object: nil)
}
    
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

Getting Keyboard Frame


In notification, that will be sent to observer selector, contain information about keyboard frame. We can get this frame using following way.
@objc func handleKeyboardShow(notification: Notification) {
    print("Keyboard will show")
    if let userInfo = notification.userInfo {
        if let keyboardFrameValue = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue) {
            let keyboardFrame = keyboardFrameValue.cgRectValue
            print(keyboardFrame)
            // (0.0, 465.0, 414.0, 271.0)
        }
    }
}
There is the same code for getting keyboard frame when keyboard shown and hidden. So we can move it to separate method and invoke it from corresponding listeners.
@objc func handleKeyboardShow(notification: Notification) {
    print("Keyboard will show")
    handleKeyboardMoving(isVisible: true, notification: notification)
}
    
@objc func handleKeyboardHide(notification: Notification) {
    print("Keyboard will hide")
    handleKeyboardMoving(isVisible: false, notification: notification)
}
    
func handleKeyboardMoving(isVisible: Bool, notification: Notification) {
    if let userInfo = notification.userInfo {
        if let keyboardFrameValue = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue) {
            let keyboardFrame = keyboardFrameValue.cgRectValue
            print(keyboardFrame)
        }
    }
}
As we can see when keyboard is shown keyboard frame has less Y coordinate then keyboard is hidden.
Keyboard will show
(0.0, 465.0, 414.0, 271.0)

Keyboard will hide
(0.0, 736.0, 414.0, 271.0)

Keyboard Visibility as Global Property in AppDelegate


If we want to know anywhere in our app whether keyboard shown or hidden we need to create global variable for this purpose. We can make it in AppDelegate class. So, now AppDelegate is observer for visibility state of keyboard.
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    var isVisible = false

    func application(_ application: UIApplication, didFinishLaunchingWithOptions
        launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        NotificationCenter.default.addObserver(self, selector: #selector(handleShow),
                                               name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(handleHide),
                                               name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        
        return true
    }
    
    @objc func handleShow()
    {
        isVisible = true
    }
    
    @objc func handleHide()
    {
        isVisible = false
    }
    
}
Now in View Controller we can get AppDelegate instance of our application and get isVisible property of it.
let status = (UIApplication.shared.delegate as! AppDelegate).isVisible
keyboardStatusLabel.text = "\(status)"
Keyboard is hidden and visible status is false

Keyboard is shown and visible status is true

Keyboard Visibility Listener as Singleton Class


We can create Singleton Class (only one instance of this Class will exist). There are a special methods: start and stop.  In start method this class will add self as observer for showing and hiding keyboard. In stop it will remove itself from observing. When visibility of keyboard is changed then instance variable isVisible will be updated(it has value false when initialized).
import Foundation

class KeyboardStateListener {
    
    static let shared = KeyboardStateListener()
    
    var isVisible = false
    
    func start() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleShow),
                                               name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(handleHide),
                                               name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    
    @objc func handleShow()
    {
        isVisible = true
    }
    
    @objc func handleHide()
    {
        isVisible = false
    }
    
    func stop() {
        NotificationCenter.default.removeObserver(self)
    }
}
We need to start this this listener in AppDelegate.
func application(_ application: UIApplication, didFinishLaunchingWithOptions
    launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
    KeyboardStateListener.shared.start()
        
    return true
}
Now we can use it anywhere in our app and get the current state of the keyboard
keyboardStatusLabel.text = "\(KeyboardStateListener.shared.isVisible)"

GitHub Source Code

There is source code for this project on github

6 comments:

  1. There are many articles circulating on internet that exaggerate about Custom Designed Websites. But your article is an exception that made me understand it without any difficulty.

    ReplyDelete
  2. Thank you for sharing this important and useful information in this article. Best Custom Websites

    ReplyDelete
  3. Thank you Sir, you made it easy as pie. Now i am able to understand and have enough knowledge about this. It is only because of you.
    Custom Designed Websites

    ReplyDelete
  4. This is a great article! Thank you very much. I really need these suggestions. An in-depth explanation is of great benefit. Incredibly inspiring to see how you write. Custom Website

    ReplyDelete
  5. Thank you for sharing this important and useful information in this article. This is very helpful for us.
    Mobile Performance Meter Hack

    ReplyDelete
  6. This is an excellent article. Your essay is very easy to understand. Thank you for providing us with this useful information.
    SEO Company NYC

    ReplyDelete