Chapter 3.  Creating a Contact Detail Page

The previous chapters focused on creating an overview page. You learned how to create an overview of contacts with a UITableView and UICollectionView. Both of these pages lacked something that is essential in almost any iOS application: navigation. Users expect to be able to tap on items in an overview and to be taken to a detail page that discloses more information about the object they tapped. Our app currently does not do this.

You'll learn how to set up navigation by using storyboards and segues. Then, you'll see how to pass data between views, which will make setting up detail pages for contacts a breeze.

Also,  the HelloContacts app is currently built with just the iPhone in mind. In reality, iOS runs on two devices: iPhone and iPad. This chapter will explain how to design for all screen sizes. You'll learn how to make use of Auto Layout and Size Classes - two tools Apple offers to create adaptive layouts that work on virtually any device.

Layouts with many elements that are positioned in relation to each other can be quite complex and tedious to set up with Auto Layout. In iOS 9, the UIStackView appeared on iOS. In this chapter, you'll learn how this component takes some of the pain out of manually laying out elements.

Throughout this chapter, we'll cover the following topics and use them to create a good-looking contact detail page that will work on any device:

  • Universal applications
  • Segues
  • Auto Layout
  • UIStackView
  • Passing data between view controllers

Let's dive right into universal applications, shall we?

Universal applications

Many users own more than one mobile device. A lot of people own both iPads and iPhones, and they switch between them all the time. This leads users to expect their favorite apps to be available not only on the iPhone, but also on the iPad.

Ever since Apple launched the iPad, it has allowed developers to create universal apps. These are apps that run on both the iPhone and the iPad. Developers used to create interface files for each device separately or jump through hoops to share the layout between devices in an adaptive way.

Over time, more screen sizes were added, and the available tools to create a universal, adaptive layout got a lot better. Nowadays, we use a single storyboard file in which a layout can be previewed on any screen size currently supported by Apple. You can even reuse most of your layouts and just apply some tweaks based on the available screen's real estate.

If your apps are not adaptive at all, you're giving your users a sub-par experience in a lot of cases. Users expect their favorite apps to be available on each iOS device they own, and Apple actually helps your users if you don't provide a universal app. According to Apple, an iPhone app should be capable of running on the iPad at all times. If you don't support the iPad, your users will be presented with a scaled up, ugly-looking version of your app. This isn't a great experience, and it often takes minimal changes to add support for adaptive layouts that will look good on any device. To do this, you can make use of Size Classes.

Size Classes is a property that belongs to a UITraitCollection. A trait collection describes the traits for a certain view or view controller. Some of these traits are relevant to the amount of available screen space. Others describe force touch capabilities or the color gamut of the screen. For now, we'll focus on Size Classes. There are only two size classes: Regular and Compact. The following is a list of devices and Size Classes you'll encounter on them:

  • iPhone 6(s) plus:
    • Portrait orientation: Compact width x Regular height
    • Landscape orientation: Regular width x Compact height

  • iPhone 6(s) and smaller:
    • Portrait orientation: Compact width x Regular height
    • Landscape orientation: Compact width x Compact height

  • iPad and iPad pro (all sizes):
    • Portrait orientation: Regular width x Regular height
    • Landscape orientation: Regular width x Regular height

The preceding list is not exhaustive. The iPad supports multitasking since iOS 9, which means that the width of the Size Class switches between Regular and Compact, depending on the size available to your application.

Note

Don't use Size Classes as an indication of the device a user is holding. The iPad can look a lot like an iPhone if you just base your assumptions on which Size Class is set for the width. If you really need to know the type of device the user is holding, you should check the userInterfaceIdiom property in UITraitCollection.

The HelloContacts app you were working on was created for the iPhone; this is the setting you picked when you first created the app. Try running your app on an iPad simulator and see what happens. The layout looks bad because it's just an enlarged iPhone app. Not such a great experience, is it?

Universal applications

Enabling your app to be universal isn't very complex. All you have to do is go to your project settings and select the Universal option in the drop-down menu of your device. Once your app is universal, it will look a lot better. However, your app doesn't support multitasking on the iPad yet.

If you want to add multitasking for the iPad (and you do), your app needs to work on all interface orientations. However, on the iPhone, it's recommended that the app should not support the upside-down interface orientation. It's possible to specify the device-dependent interface orientation setting in the Info.plist file. This will make it possible for your app to support all orientations on the iPad and support all orientations except the upside-down orientations for the iPhone. To do this, first uncheck all of the supported interface orientations in your project settings. Your settings should look like the following screenshot:

Universal applications

Next, open the Info.plist file and search for the Supported interface orientations key. Remove this key and add two new keys, Supported interface orientations (iPad) and Supported interface orientations (iPhone). Add all of the possible orientations to the Supported interface orientations (iPad) key, and add all except for the upside-down orientation on the iPhone. You should end up with the settings listed in the following screenshot:

Universal applications

This is all of the work required to set up a universal version of HelloContacts. Build and run the app to see what it will look like when it actually adapts to the iPad's layout. It looks much better than before, and you didn't even have to change any code! In the previous chapter, we implemented some special behavior for the cell deletion so the app wouldn't crash if a contact got deleted on an iPad. The iPad doesn't display action sheets as the iPhone does; it uses a popover instead. Let's check that out now. Long press on a contact to see the popover appear, as shown in the following screenshot:

Universal applications

The popover appears, but as shown in the preceding screenshot, its positioning is kind of awkward. Let's take a look at how the popover is positioned and how to fix it. The current implementation to present the popover looks like this:

if let popOver = confirmDialog.popoverPresentationController { 
    popOver.sourceView = cell 
} 

This implementation sets the sourceView property for the popover. This property tells the popover which view will contain it. So, in this case, the cell will act as the parent view for the popover view. The popover has another property called sourceRect. This property specifies a box in which the popover should be anchored. The coordinates for this box should be relative to the containing view's coordinates. Update the implementation with the following code to position the popover's anchor at the center of the contact image view:

if let popOver = confirmDialog.popoverPresentationController { 
    popOver.sourceView = cell 
 
    if let cell = cell as? ContactCollectionViewCell { 
        let imageFrame = cell.contactImage.frame 
 
        let popOverX = imageFrame.origin.x + 
imageFrame.size.width / 2 
        let popOverY = imageFrame.origin.y + 
imageFrame.size.height / 2 
 
        popOver.sourceRect = CGRect(x: popOverX,  
y: popOverY,  
width: 0,  
height: 0) 
    } 
} 

It might not seem like anything special, but this popover code is actually the first piece of adaptive code that you've written. It checks the current environment by looking for a popoverPresentationController property. This property is only available in certain environments, and if it is, you can configure a special part of code that only applies to that specific environment. The beauty in this is that no assumptions are made about the device or screen size; it simply checks the capabilities of the current environment and acts based on them. If Apple were to implement this same popover behavior for the iPhone tomorrow, your code would still work perfectly.

One last interesting aspect to look at right now is multitasking. You saw how to enable support by modifying the Info.plist file. Swipe left from the right edge of the simulator screen and pick an app to be opened side by side with HelloContacts. You should be able to change the available size for HelloContacts and change the orientation on the iPad, and the layout will update accordingly.

Congratulations! You just enabled HelloContacts to run on any iOS device with any possible screen size. Isn't that amazing? Now, let's take a look at navigation.

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

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