Managing the iOS Keyboard for All Configurations

Last time I wrote a blog post I took you deep into the woods of Core Data. Today, I’d like to talk about something that just about every iOS app has to deal with, the on-screen keyboard.  That keyboard can cover just about half the screen on iPhones and a good portion of iPad screens too.  If you’re not careful, important content (like the UITextField your user is typing into) will be hidden by the keyboard at the start of editing.  You can’t just count on one size per device per orientation either.  What if the next release of iOS changes the size of the keyboard?

 What you need is a dynamic solution to cover all your keyboard needs regardless of orientation and keyboard height.  Apple has a great guide on managing the keyboard, but their explanation is completely in Objective-C, and does not explain how to set up a UIScrollView properly.  This post will guide you through a sample Swift app that demonstrates the proper way to set up a view ready for any iOS keyboard size.

  1. Create a new Single View Application iOS project in Xcode.

image20.png

  1. Name it whatever you’d like.  I named mine “EFKeyboardTutorial”.  Make sure you change the language to Swift before hitting Next.

image28.png

  1.  Navigate to the storyboard of your new project and add a UIScrollView to the center of the view provided to you.

 image19.png

  1.  With the scroll view selected click on the “Add New Constraints” button at the bottom right of the Storyboard toolbar.  It’s the small icon with the square in the middle that looks kinda like a tie fighter.

 image15.png

  1. We want the scroll view to take up the entire view.  The goal will be that users won’t be able to scroll the view unless the keyboard is extended.  In order to have the scroll view take up the entire screen, click on the dropdown boxes for both the top and bottom constraints and select “View” instead of using the layout guides.

 image21.png

image02.png

  1. Unselect “Constrain to margins”, set all the values to 0, and enable all the struts just like the image shows.  Then click on the “Add 4 Constraints” button.

 image01.png

  1. Your screen should now look like the image below.  The orange lines mean that you have satisfied all necessary constraints with no ambiguity.  But right now the view isn’t where it will be at run time.  

 image31.png

  1.  In order to update all the views to their proper positions and sizes at run time, click on the triangle icon button at the bottom right of the Storyboard toolbar and in the “All Views in View Controller” select “Update Frames”.  (You could also choose the “Update Frames” option in the “Selected Views” section provided you still have the scroll view selected.)

 image00.png

  1. Now that our scroll view fills the entire view, we can now add the view that will hold all our content.  Find the UIView in the Object Library and drag it into the middle of your scroll view.

image04.png 

  1. With your new view selected open the “Add New Constraints” window again and add these 4 new constraints.

 image25.png

  1. Your screen should look like the image below.

 image14.png

  1. What gives?  You added the exact same constraints as the scroll view.  Why are these constraints in red when the scroll view’s constraints were in orange?  The red lines indicate that you do not have enough constraints to properly lay out the view, or you have conflicting constraints.  In this case you don’t have enough constraints.  The view is embedded into the scroll view and the scroll view’s content size is dynamic based on its embedded views.  The four constraints we’ve added won’t actually determine the height and width of the view.  We need to provide it.  One of the easiest ways to do this is to set the height and width of the view equal to the height and width of the scroll view.  Holding the “control” button, click and drag from the view to the scroll view.

image08.png

  1. Select “Equal Widths”.  Then control-click and drag from the view to the scroll view again and select “Equal Heights”.

image23.png

  1. Your screen should now look like the image below.

image11.png

  1. Sweet!  This means that all your constraints are set properly.  Go ahead and update your frames like you did in step 8.  Your screen should look like the image below.

image17.png

  1. Now you have a clean slate in which to build your initial app view.  Because the content view is the same size as the scroll view, scrolling won’t be enabled, and it will look as if there is no scroll view when we run our app.  This is great, because now we can increase the size of our content view by the size of the keyboard when it appears, and the user will still be able to scroll to see the entire view.  Now add a UITextField close to the bottom of the view.

  2. Control-click and drag from your new text field to its superview, and add these constraints: “Bottom Space to Container”, “Center Horizontally in Container”, and set the width to some reasonable width.  (A couple things to note: In order to see the “Bottom Space to Container” constraint you must control-drag down from the text field, and in order to see the “Center Horizontally in Container” you must control-drag either up or down from the text field.)

 image29.png

image09.png

image24.png

image16.png

  1. Our initial app view is completely built now.  I set my content view’s background color to clear, and added a light grey background color to the scroll view’s superview to make everything a little more obvious, but you don’t need to do that if you don’t want to.
  2. Now we need to connect elements of our view to a view controller.  Conveniently, the view we’ve been working on was already connected to a ViewController class when we created our project.  To connect the elements click on the “Assistant editor” button on the top left of the Xcode window.  It looks like a venn diagram.

 image05.png

  1. Locate your scroll view in the “Document Outline” and control-drag from it to right above the “viewDidLoad()” function.  You can see this in the image below.

 image22.png

  1.   Make sure your new connection is an “Outlet” and name it “scrollView”.

 image12.png

  1. Great!  Now we can get to coding.  Following Apple’s guide, we should register for two notifications: UIKeyboardDidShowNotification and UIKeyboardWillHideNotification.  However, I’ve found that the animation looks much better if you use UIKeyboardWillShowNotification.  Below your “viewDidLoad()” function add this code:

override func viewDidAppear(animated: Bool) {

        super.viewDidAppear(animated)

       

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardWasShown(_:)), name: UIKeyboardWillShowNotification, object: nil)

       

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardWillBeHidden(_:)), name: UIKeyboardWillHideNotification, object: nil)

    }

   

    override func viewDidDisappear(animated: Bool) {

        super.viewDidDisappear(animated)

       

        NSNotificationCenter.defaultCenter().removeObserver(self)

    }

image18.png

  1. You will notice a couple errors with the above code.  Mainly the functions, “keyboardWasShown(_:)” and “keyboardWillBeHidden(_:)” do not exist.  Add them now:

func keyboardWasShown(aNotification: NSNotification) {

       

        print(“Keyboard was shown”)

    }

   

    func keyboardWillBeHidden(aNotification: NSNotification) {

       

        print(“Keyboard was hidden”)

    }

 image13.png

  1. Run your app either in the simulator or a device.  When you tap on the text field, the keyboard should appear, and you should see “Keyboard was shown” in your log.  If you chose to run this on an iPhone, you won’t be able to dismiss the keyboard!  This is a real problem.  Let’s address this now.
  2. Go back to your storyboard.  Find the “Tap Gesture Recognizer” in the “Object Library” and drag it to the middle of your view.

 image06.png

  1. Then, using the “Assistant editor” again, control-drag from the “Tap Gesture Recognizer” in the outline to your ViewController code.  Make sure you drag it somewhere between two functions.

 image03.png

  1. This time change the Connection to “Action” and the Name to “userTappedBackground”.

 image10.png

  1. In the function that was created for you add this line:

@IBAction func userTappedBackground(sender: AnyObject) {

       

        self.view.endEditing(true)

    }

 image30.png

  1. Go ahead and run your app now.  You should now be able to show the keyboard by tapping on the text field and hide the keyboard by tapping on the background on any device.  The log should also tell you when the keyboard is shown and when it is hidden because of the print() statements you’ve added to your code.  The keyboard should also completely cover your text field for you to get the full benefit of this tutorial.  If it does not, adjust your constraints until it does.

 image07.png

  1. Here is where we implement the rest of Apple’s guide.  Except this time we’ll do it in Swift!  Add the following code to your “keyboardWasShown(_:)” and “keyboardWillBeHidden(_:)” functions:

func keyboardWasShown(aNotification: NSNotification) {

       

        print(“Keyboard was shown”)

       

        guard let info = aNotification.userInfo else {

           

            print(“Error: No info from notification”)

            return

        }

       

        guard let kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size else {

           

            print(“Error: No size for keyboard in info”)

            return

        }

       

        print(“Size: (kbSize)”)

       

        let contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0)

        self.scrollView.contentInset = contentInsets

        self.scrollView.scrollIndicatorInsets = contentInsets

    }

   

    func keyboardWillBeHidden(aNotification: NSNotification) {

       

        print(“Keyboard was hidden”)

       

        let contentInsets = UIEdgeInsetsZero

        self.scrollView.contentInset = contentInsets

        self.scrollView.scrollIndicatorInsets = contentInsets

 

    }

 image26.png

  1. Run your app now and tap on the text field.  Notice how the field animates to just above the keyboard.  You can even scroll the screen to see the entire view!  And when you dismiss the keyboard, notice how you can no longer scroll.  It’s like magic!

image27.png

 

I hope you enjoyed this tutorial and learned something.  If for any reason your code doesn’t work or maybe you’re too lazy to go through all 31 steps, you’re more than welcome to download this entire project from GitHub: https://github.com/SWBerard/iOS-Keyboard-Handling-Tutorial.