Skip to content

Instantly share code, notes, and snippets.

@chenr2
Last active February 2, 2016 16:32
Show Gist options
  • Save chenr2/39b6f1f00ff020b99d46 to your computer and use it in GitHub Desktop.
Save chenr2/39b6f1f00ff020b99d46 to your computer and use it in GitHub Desktop.
Swift: dealing with keyboards

The keyboard keeps obscuring my content

TODO: WIP. Need to test next time I integrate this.

See Greg Heo's video ScrollView tutorial on raywenderlich.com.

Text boxes can get covered up by the keyboard, especially on 3.5 inch screens (4s). The first step is to embed the page contents inside a UIScrollView.

@IBOutlet weak var scrollview: UIScrollView!

I just need to see this one view

Call scrollRectToVisible to bring a view out from under the keyboard.

scrollview.scrollRectToVisible(myTextView.frame, animated: true)

Just shift all the page contents up and down

It's a lot of boilerplate, but sometimes you just need to shift the whole thing up and down with the keyboard.

First hook into the keyboard notifications in viewDidLoad.

override func viewDidLoad() {
    super.viewDidLoad()
    keyboardHeightRegisterNotifications()
}

Wire up a selector for UIKeyboardWillShowNotification and UIKeyboardWillHideNotification. Don't forget the : because we need to access the userInfo object.

func keyboardHeightRegisterNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

A good neighbor always cleans up after his dog.

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

Each selector we defined takes a NSNotification parameter. For each one, just call a helper method and pass in a Bool to indicate up or down.

func keyboardWillShow(notification: NSNotification) {
    adjustInsetForKeyboardShow(true, notification: notification)
}
    
func keyboardWillHide(notification: NSNotification) {
    adjustInsetForKeyboardShow(false, notification: notification)
}

Now to actually move the thing up and down. Grab the keyboard height from the NSNotification and move the scrollview contentInset up or down.

To spare us from some gotchas down the road, we don't actually move the keyboard down (show ? 1 : -1) -- rather we just zero out the state.

func adjustInsetForKeyboardShow(show: Bool, notification: NSNotification) {
    let adjustmentHeight = getKeyboardHeight(notification) * (show ? 1 : 0)
    scrollview.contentInset.bottom = adjustmentHeight
    scrollview.scrollIndicatorInsets.bottom = adjustmentHeight
}

Lots of helper functions. This one unwraps the keyboard height from the NSNotification object. It's important to use the UIKeyboardFrameEndUserInfoKey from userInfo. Don't use UIKeyboardFrameBeginUserInfoKey, or you'll find yourself driving a car using your rearview mirror.

func getKeyboardHeight(notification: NSNotification) -> CGFloat{
    let userInfo = notification.userInfo ?? [:]
    let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
    return CGRectGetHeight(keyboardFrame)
}

Putting it all together

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scrollview: UIScrollView!

    override func viewDidLoad() {
        super.viewDidLoad()
        keyboardHeightRegisterNotifications()
    }

    func keyboardHeightRegisterNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
    }
    
    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
    func keyboardWillShow(notification: NSNotification) {
        adjustInsetForKeyboardShow(true, notification: notification)
    }
    
    func keyboardWillHide(notification: NSNotification) {
        adjustInsetForKeyboardShow(false, notification: notification)
    }
    
    func adjustInsetForKeyboardShow(show: Bool, notification: NSNotification) {
        let adjustmentHeight = getKeyboardHeight(notification) * (show ? 1 : 0)
        scrollview.contentInset.bottom = adjustmentHeight
        scrollview.scrollIndicatorInsets.bottom = adjustmentHeight
    }
    
    func getKeyboardHeight(notification: NSNotification) -> CGFloat{
        let userInfo = notification.userInfo ?? [:]
        let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
        return CGRectGetHeight(keyboardFrame)
    }
    
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment