Adjusting the bottom section for small screens

The layout you have so far looks pretty good on the iPad. However, it's just too cramped on the iPhone in portrait mode. Let's create some room by changing it to a single-column layout. First, select iPhone view and click on the Vary for Traits button. This time, make sure that you only vary for the width. The easiest way to pull off a change this big is to rearrange the view first without modifying the constraints yet. Rearrange the views so they look as shown in the following screenshot:

Once you have rearranged the views, it's a good idea to add constraints that you know are missing. This isn't always straightforward but with some practice, you should get the hang of this pretty soon. Always make sure that each view can figure out its x and y position and its width and height.

In this case, the following constraints are missing:

  • Top view with notes to the left side of the content view
  • Vertical spacing between the top and bottom view
  • Bottom view to the right side of the content view

Add the constraints after you have started your Vary for Traits by pressing Ctrl and dragging as you have done before. You'll end up with a lot of errors and red lines. This is because you haven't disabled the constraints that were created for the two-column layout. To fix the errors, the following constraints that only apply to the two-column layout must be removed for the compact width variation:

  • Vertical spacing between the view with the contact information and the contact name label
  • Horizontal spacing between the former left and right view
  • Equal width constraint for the two bottom views

To remove the mentioned constraints, select the top view and look for the Leading Space to: View constraint. Click this constraint and delete it to disable it for the Compact Width version of your layout. Make sure you are still in Vary for Traits mode when you do this. Otherwise, the constraint will be deleted for all size variations. Do the same for the other two constraints. You can find these constraints by selecting either of the views related to the constraint you're looking for. Finally, select the vertical spacing constraint for the top and bottom view and modify the constant to 8; this will provide nice spacing between the two sections. You're done modifying the constraints now; no conflicts should remain, and your layout should now look good on all devices. Check out the plus-sized iPhone in particular; it will switch between the single- and two-column layouts! Pretty cool, isn't it? If you run the app in landscape on other devices, you'll notice that even though the layout is taller than the screen, the scroll view makes sure all content is accessible.

Before you deep-dive into Auto Layout on the code side, there's one last thing that needs to be fixed. Whenever the keyboard appears, the scroll view should resize so a user can still see the entire page. To do this, you need to create an @IBOutlet object for the bottom constraint of the scroll view, and then you will need to programmatically set the constant for the bottom constraint to the height of the keyboard. To get started, create a new UIViewController subclass (File | New | File...) and name it ContactDetailViewController. Assign this class to the contact details screen's view controller in Interface Builder.

Define the following @IBOutlet object in ContactDetailViewController.swift and connect it by dragging from the Connections Inspector to the scroll view's bottom constraint in the Document Outline:

@IBOutlet var scrollViewBottomConstraint: NSLayoutConstraint!
If an item is hard to find or access in the visual view hierarchy, you can look for the view or constraint in the Document Outline. Once you have found the thing you wish to connect to an @IBOutlet object, you can Ctrl + drag from the outlet in the Connections Inspector to the item in the Document Outline to configure the connection.

Next, add the following code to ContactDetailViewController.swift:

override func viewDidLoad() {
  super.viewDidLoad()

  NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear),
                                         name: UIApplication.keyboardWillShowNotification,
                                         object: nil)

  NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide),
                                         name: UIApplication.keyboardWillHideNotification,
                                         object: nil)

}

The preceding code subscribes the details page to keyboard notifications. Whenever the keyboard appears, the system posts a notification to an object called NotificationCenter that any object can listen to. Whenever the notifications are fired, a selector is executed on the view controller. This selector points to a function in the view controller. The code as it won't compile just yet because you still need to implement the keyboardWillAppear and keyboardWillHide methods. Add the following implementation for these methods:

@objc func keyboardWillAppear(_ notification: Notification) {
  guard let userInfo = notification.userInfo,
    // 1
    let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double
    else { return }

  // 2
  scrollViewBottomConstraint.constant = keyboardFrame.cgRectValue.size.height
  UIView.animate(withDuration: TimeInterval(animationDuration), animations: { [weak self ] in
    // 3
    self?.view.layoutIfNeeded()
  })
}

@objc func keyboardWillHide(_ notification: Notification) {
  guard let userInfo = notification.userInfo,
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double
    else { return }

  scrollViewBottomConstraint.constant = 0
  UIView.animate(withDuration: TimeInterval(animationDuration), animations: { [weak self ] in
    self?.view.layoutIfNeeded()
  })
}

The preceding code snippet first reads some values from the userInfo dictionary on the notification object. The keyboard's final frame and the animation duration are extracted from this dictionary. Next, the scroll view's bottom constraint is updated so it is pushed upward by the keyboard's height. To animate this change, layoutIfNeeded() is called on the view controller's view inside of an animation block. Calling this method inside of an animation block ensures that the Auto Layout updates are performed with an animation.

When the keyboard hides, a similar flow is used except the scroll view's bottom constant is reset back to 0.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset