How to add a modal to your UI in Swift 2, Xcode 7

As a part of an iOS course I'm taking through Udacity I'm creating an app to record and play audio. This article is part of an assignment for that course. 

This guide explains how to create a modal that confirms a specific user action within an app using Swift 2.0 and Xcode 7.

For the app I'm building, the modal will request that the user confirm the start of audio recording.


Summary

  • Add a new Cocoa Touch Class file of type "UIViewController."
  • Drag a new View Controller onto the storyboard, set its class to match file you just created.
  • Choose a dark background color for the initial View within this new View Controller and lower its opacity.
  • Drag a new View onto your new View Controller in the storyboard, this is the sub View that will hold the content of the modal that appears.
  • Provide constraints to center align the sub View vertically and horizontally.
  • Add two buttons, name them "Start" and "Cancel" and give them constraints.
  • Run code in the View Controller after clicking a button in the modal using delegation

Details

Add a new Cocoa Touch Class file of type "UIViewController."

Go to "File > New" and select "File..." In the Xcode 7 Menu

Choose "Cocoa Touch Class" under "iOS Source" and click "Next"

Give your new file a classname and choose a Subclass of "UIViewController"


Drag a new View Controller onto the storyboard and set its class to match the file you just created.

Drag it from the bottom of the Utility window onto your storyboard

Link the storyboard View Controller to the View Controller swift file you created by adding a custom class of the same name.


Choose a dark background color and lower its opacity.

First click in the middle of the View Controller to select the View, then click the Attributes inspector in the Utility window

Drag a new View onto your new View Controller in the storyboard to add a sub View.

This the box that will hold the content of the modal that appears.

Pick a size that works for your needs.

Drag the view to the center. This aligns the view in the storyboard, but you'll still need to add constraints in order to keep it aligned in the app on your phone.


Provide constraints to center align the sub View vertically and horizontally.

Note: If you've added constraints but they're red, make sure you've added both inner constraints for width and height and outer constraints for positioning vertically and horizontally. The constraints will turn blue once you've satisfied the minimum number of requirements for them to act.

For inner constraints, Control + drag diagonally, stay within the sub View, and choose "Width" and "Height" in the popup that appears 

For outer constraints, Control + drag diagonally out to the sub View's containing View and choose "Center Horizontally in Container" and "Center Vertically in Container"

Add two buttons, name them "Start" and "Cancel" and give them constraints. Also add a label if you would like the modal to display a message.

 Drag the buttons from the utility window to your sub View. Add constraints. The sub View is the "Container" for the buttons so when adding outer constraints you don't need to drag all the way out to the the initial View.

Drag the buttons from the utility window to your sub View. Add constraints. The sub View is the "Container" for the buttons so when adding outer constraints you don't need to drag all the way out to the the initial View.

When you're done your modal should look something like this.

Finished Modal


Create a segue from the original View Controller to the new modal View Controller you've created

Control drag from the button that you want to launch the modal onto your modal's View Controller and choose "Present Modally"

At this point you can build your app and the modal will appear when the button you just connected to it with a segue is pressed.


So now lets have the modal buttons dismiss the modal and then run code on the original view that called it. I accomplished this using delegation

First let's write the code we want to execute. Since my app is for recording audio and the modal is a confirmation with two options, I placed my code in two functions called "startRecording" and "cancelRecording." I placed this code on the original View Controller.

Write the code that will execute when a button on the modal is pressed.

Place the code that you intend to execute from the modal buttons in the View Controller that originally called the modal.

Add a prepareForSegue override

(I recommend imagining GOB Bluth saying 'prepare for segue')

Override the built in prepareForSegue function and pass the current View Controller object that contains the functions you just wrote, to the destination View Controller which is your modal's view controller. Note: I'm describing how I currently understand this to work, but I'm new to Swift, if you know better please correct me.

Use "prepareForSegue" to send your current View Controller ("self") to the destination View Controller (modalConfirmRecord). NOTE: You can set an identifier for a View Controller using the Utility window (not shown in this article). As you can see I set the identifier for my modalConfirmRecord View Controller to "confirmRecordingSeque" and use it to selectively send the object to just that View Controller.


Create the delegate

Define the protocol to include the functions that you want to execute, put that in a variable within your class and use that variable within the actions associated with your modal buttons.

First Green Arrow: In the modal's View Controller set up the delegation using the "protocol" keyword outside of the class declaration. In my case the methods it will run are the "cancelRecording" and "startRecording" methods, so those need to be included in the protocol for the delegate.

Second Green Arrow: Within the class define a variable with the same type as the protocol. In my case I called it "delegate."

Third and Fourth Green Arrow: Use Button actions to fire the built in "dismissViewControllerAnimated" and in the body of that run the code you want to execute on the View Controller that called the modal.

For example, in my case the "Start" button action runs the dismissViewController and which then runs the "self.delegate?.startRecording()" to run the "startRecording."


Add the delegate type to the modal calling View Controller

Finally, back on the View Controller that calls the modal's View Controller, add the delegate type to its class. In my case it's called "modalConfirmRecordDelegate"

17_AddDelegateType.png

And that should do it. You now have a modal and its buttons perform actions on code from a different view controller. I hope this was helpful!


The resources I found most helpful while writing this tutorial

If you need more details on a specific item, especially the delegate aspects of this article, these resources are a great place to start.

Apple Documentation about dismissing view controllers

Apple Documentation on constraints

Tim Sanders blog about modals in Swift

Swiftly video about Delegates especially starting around 11:05

DJ Spiess / Deejeu video about transferring data between views in iOS 9