Implementing navigation with segues

Most good applications have more than a single screen. I bet that most app ideas you have in your head involve at least a couple of different screens. Maybe you'd display a UITableView or UICollectionView and a details view, or maybe users will drill down into your app's contents in some other way. Maybe you don't have any real details views but instead you would like to show some modal windows.

Every time your user moves from one screen to another, they're navigating. Navigation is a very important aspect of building an app, and it's absolutely essential that you understand the possibilities and patterns for navigation on the iOS platform. The easiest way to get started with navigation and to explore the way it works is to experiment inside of your Main.storyboard file.

Up until now, we've used the storyboard to create the layout for just a single screen. However, as the name implies, your storyboard isn't there for just a single screen. The purpose of the storyboard is to lay out and design the entire flow of your app. Every screen and transition can be designed right inside your storyboard file. We'll use the storyboard to add a new UIViewController that will function as a details page for the contacts. The actual contents won't be added right away; a single UILabel will have to do for now, so that you can explore different kinds of transitions in your app before implementing a details page.

After opening the Main.storyboard, drag a UIViewController from the Object Library on the right side of your Interface Builder screen. Drop it next to the view controller that has the current layout in it. You'll see that you now have two separate screens that you can design. Next, drag a UILabel out from the Object Library and drop it inside the new view controller. Place the UILabel in the center of the view and enter some text in the label so you can easily identify this as your second view controller later. Then, add some constraints to center the UILabel in its parent view by clicking on the Pin button in the bottom-right corner and selecting the Horizontal center and Vertical center constraints.

Now that we have a second view controller to display, and some content added to it, let's connect the first and second screens in our app. To do this, we'll create a selection segue. A segue is the transition from one screen to the next. This transition does not necessarily have to be animated. Any time you use a storyboard to move from one screen to the next, you're using a segue. Some segues are triggered when a button is tapped. These are called action segues. Segues that can only be triggered through code are called manual segues.

You can also connect a cell in a UITableView or UICollectionView to a screen. This is called a Selection segue; it is triggered whenever a cell is selected. A segue that you've already seen is called the relationship segue, which is the connection between UINavigationController and UIViewController that contains the UICollectionView with contacts.

To display the second view controller in the app, we'll use the selection segue; we want the second view controller to display when the user taps on a contact in the collection view. In the Main.storyboard, select the contact collection view cell. Now, press the Ctrl key while you drag from the cell to the second view controller. After doing this, a list of options will pop up where you can pick how to present this new view controller. For example, try the present modally segue. This will animate the new view controller up from the bottom of the screen.

This isn't really the style we're looking for in this app. A new contact should be pushed onto the current navigation stack so users can naturally move back to the contacts overview when they desire; it shouldn't create a new navigation context like present modally does. Ideally, we want a back button to appear in the top-left corner so users can go back to the contacts overview very easily.

The Show segue will do this for you. Whenever the presenting view controller is embedded inside a navigation controller, the Show segue will push the presented view controller on-to the current navigation stack. This means that the back button is automatically displayed, which is exactly what we're looking for. Go ahead and try it out.

Even though this behavior is perfect for HelloContacts, the transition from the overview to the next screen just isn't quite what it should be. If you look closely, the bounce animation on the collection view cell doesn't get a chance to finish before the new view controller is pushed. This looks sloppy, and it's a shame our animation doesn't get enough time to shine. This is a perfect time to use a manual segue; a segue we'll trigger from the code whenever we want to. By using a manual segue, we can take full control over when the next view controller is presented to the user. This is perfect for us because we can allow the animation to finish and show the next view controller afterwards.

In the Main.storyboard, select the connection between the overview and the second view controller and press the Backspace key to delete it. Create a new, manual segue by dragging from the yellow circle in the top section of your overview view controller to the details view controller. When the modal comes up, select the Manual segue. Now, select the segue you just created and set detailViewSegue as the value for the identifier field in the Attributes Inspector.

To trigger the segue at the right time, open ViewController.swift and update the following code in the collectionView(_:didSelectItemAt:) method; the updated code is highlighted:

func collectionView(_ collectionView: UICollectionView,  
didSelectItemAt indexPath: IndexPath) {

guard let cell = collectionView.cellForItem(at: indexPath) as?
ContactCollectionViewCell else { return }

UIView.animate(withDuration: 0.1,
delay: 0,
options: [.curveEaseOut],
animations: {
cell.contactImage.transform = CGAffineTransform(scaleX:
0.9, y: 0.9)
}, completion: { finished in
UIView.animate(withDuration: 0.1,
delay: 0,
options: [.curveEaseIn],
animations: {
cell.contactImage.transform = CGAffineTransform.identity
},
completion: { [weak self] finished in
self?.performSegue(withIdentifier:
"detailViewSegue",
sender: self)
}
)
})
}

By adding a completion handler to the animation that resets the contact image back to its original size, you can trigger the manual segue after the entire animation is complete. A manual segue is triggered by calling the performSegue(withIdentifier:sender:) method.

The performSegue(withIdentifier:sender:) method is implemented in UIViewController and is used to programmatically trigger segues. If you build and run the app now, you'll see that the entire animation on the contact image will complete and only after the animation is done is the segue performed.

Now that you know how to use a storyboard for designing multiple screens and visually connecting them with segues, it's time to learn more about Auto Layout. Let's add some actual details to the contact details screen