Teeps

Responding to Keyboard Events in Swift

07 February 2015 by James Smith

Let’s say you have a table view where you collect some basic information from the user.

When the user selects one of the fields above, the keyboard appears and blocks the user from interacting with the switches at the bottom of the screen. Even worse, the user cannot scroll the table view to move the switches above the keyboard. You might find yourself writing something like this to solve the problem:

override func viewDidAppear(animated: Bool) {    
  super.viewDidAppear(animated)    
  NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)    
  NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardDidHide:", name: UIKeyboardDidHideNotification, object: nil)  
}

func keyboardWillShow(notification: NSNotification) {    
  if let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey]?.CGRectValue() 
    {      
      tableView.contentInset.bottom = keyboardFrame.height    
    }  
}

func keyboardDidHide(notification: NSNotification) {    
  tableView.contentInset.bottom = 0.0  
}

override func viewWillDisappear(animated: Bool) {    
  super.viewWillDisappear(animated)    
  NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)    
  NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardDidHideNotification, object: nil)  
}

This is fine for one screen, but what happens when you have to repeat this code for other screens in your app?

KeyboardObserver

KeyboardObserver is a small class that abstracts the messy parts of observing keyboard events into a single delegate callback. Here’s how it works.

Instantiate a KeyboardObserver and specify which events you would like to be notified of:

keyboardObserver = KeyboardObserver(delegate: self, eventTypes: [.WillShow, .WillHide, .DidHide])

Then tell your new keyboardObserver to begin listening for keyboard events:

override func viewWillAppear(animated: Bool) {    
  super.viewWillAppear(animated)    
  keyboardObserver?.beginObservingKeyboardEvents()  
}

You will also need to let your keyboard observer know when to stop listening:

override func viewWillDisappear(animated: Bool) {    
  super.viewWillDisappear(animated)    
  keyboardObserver?.endObservingKeyboardEvents()  
}

Finally, just implement the single method from the KeyboardObserverDelegate protocol:

func keyboardObserverDidReceiveKeyboardEvent(event: KeyboardEvent) {    
  switch event.type 
    {    
      case .DidHide:      
        tableView.contentInset.bottom = 0.0    
      case .WillHide:      
        dismissButton.enabled = false    
      case .WillShow:      
        dismissButton.enabled = true      

      if let frame = event.keyboardFrame {        
        tableView.contentInset.bottom = frame.height      
      }    default: ()    
    }  
}

The delegate method will be handed a KeyboardEvent type that you can use to access some important information about the event. Here are the public properties for KeyboardEvent:

  public let type: KeyboardEventType  
  public let keyboardFrame: CGRect?  
  public let animationCurve: UIViewAnimationOptions?  
  public let animationDuration: NSTimeInterval?

And that’s all there is to it! I think this makes it much simpler to adapt your app’s UI in response to keyboard events. Check out the demo app and code here.

Let's build your next big thing.

Contact Us