Prototyping with Xcode
Part 2
In the first part of our Prototyping with Xcode series, we built the main view of our prototype app. We also made sure it will look good on multiple iOS devices. It’s still fairly static, however. We want to start making our prototype do things.
Reminder: This tutorial requires Xcode 6.4 or above. Xcode 7 works too.
The Second View
When the user taps our camera button, we’d like to present a menu of available food photos. That menu will require a whole new view, which itself will require a new view controller. In the Object library, search for “view controller” and drag the first result onto storyboard next to your existing view controller.
The view controller pops into existence with a generic size of 600-by-600. Switch it to “iPhone 4.7-inch” in the Attributes inspector. While their placement on the storyboard doesn’t matter for running the app, it’s helpful to keep our view controllers visually organized. Drag the new controller to a position just to the right of the first.
Right off the bat, we should do three things to the new view controller that you now know how to do:
- Assign the main View a background color of HSB 30º, 70%, 70%.
- Add a Navigation Bar under the status bar area and constrain its top, horizontal center, and width to the main View.
- Add a Bar Button Item to the right side of the navigation bar.
Once you have those elements in place, change the navigation bar’s title to “Choose Image;” its Bar Tint to HSB 30º, 70%, 70%; and its Title Color to “White Color.” Uncheck the Translucency checkbox.
Select the bar button item and change its System Item to “Done” (in the Attributes inspector). Change its Tint to “White Color.”
Create Buttons
Now we’ll create our menu of images. Because each image ought to be tappable, we’ll use buttons for this purpose. Search for “Button” in the Object library and drag the first result (not the Bar Button Item) onto the image chooser view controller. Copy and paste it twice so you have three buttons in total.
For each button, delete its Title in the Attributes manager, and then set its Background to one of three assets: Breakfast1, Breakfast2, or Breakfast3.
Arrange for each button to use a different background image. Resize and arrange the buttons until you have, roughly, a row of image tiles. For each button, select it and use the Pin menu to set the Width to 120 and Height to 80.
The middle image button can remain centered in the view, so constrain it to the navigation bar with Vertical Spacing and Center Horizontally (or Center X).
Constrain the left image button to the middle button using Horizontal Spacing and Center Vertically (or Center Y).
Constrain the right image button to the middle button using Horizontal Spacing and Center Vertically (or Center Y).
Edit the button constraints so that the leading and trailing values match and vertical centering uses a constant of zero. (Any other value would create an offset from center.)
You’ll probably have several yellow frames when you’re done. We can fix all of them at once by going to the Resolve Auto Layout Issues menu and clicking Update Frames under All Views in View Controller.
Xcode can be uncooperative here. Often you’ll seem to have an object selected on the storyboard but be unable to click anything in the Resolve Issues menu — every option is grayed out. When this happens, click an empty area of the storyboard to deselect everything, select your object again, and try the menu.
It’s a good time to test our work, but if we try to run our prototype in the simulator now we’ll never see the photo chooser view. It’s not connected to any part of the main interface, so there’s no way to navigate to it. We can fix that with a quick control-drag.
Segue
Select the navigation bar photos button in the first view controller. While holding the control key, click and drag from the photos button to anywhere in the second view controller — as if you were establishing an auto layout constraint. Release the mouse button and you’ll see a popup with several “Action Segue” options available.
Segues are transitions between view controllers, and Xcode offers us four built-in transitions plus the option to supply our own (the “custom” item). Here, a simple modal popover will do the trick. Select “present modally” from the segue popup.
A connecting arrow will appear leading from the first view controller to the second. If you click on this segue arrow, you can remove it with the delete key, or tweak its behavior. Select the segue now and switch to the Attributes manager. There you’ll find a Transition menu with a few different animations available. “Cover Vertical” is the default, but you can play with the others too.
With your segue in place, run the app in the simulator and try clicking the photos button. You will instantly realize that, though you can navigate to the photo chooser, there’s no way to back out of the new view. Our “Done” button does nothing. That’s certainly something we want to fix; but for now, return to the storyboard.
Proportional Scaling
Our row of images looks good on an iPhone 6 display but won’t scale appropriately on displays of other sizes. We’re going to rework the image constraints so they scale with the device.
Select all three image buttons by holding the shift key as you click each one, and then select Clear Constraints from the Resolve Auto Layout Issues menu.
Then select the middle image button only and constrain its Vertical Spacing and Horizontal Center (Center X) to the navigation bar as before.
Now, rather than pin the image button’s width and height, we’re going to tie them to the size of the containing view. Control-drag from the image button to the view below it, and shift-select both Equal Widths and Equal Heights.
Of course, we don’t really want our image button to use the same width and height as the view around it — that would make it quite large. But we can customize these constraints so that the width and height remain proportional to the display.
Click Edit on the image button’s Equal Width to Superview constraint. (Remember, constraints can be found in the Size inspector.) In the Multiplier field, replace “1” with “3.3.” The Equal Width constraint has now become a Proportional Width constraint.
Click Edit on the image button’s Equal Height to Superview constraint. In the Multiplier field, replace “1” with “8.5.”
These proportions seem strange. Clearly the image button is not 8.5 times as tall as the entire display. In fact, the proportion is operating in reverse — it’s the display that’s 8.5 times as tall as the button. It’s always possible to reverse an auto-layout relationship by double-clicking the constraint in the Size inspector, and then selecting “Reverse First and Second Item” in either the First Item or Second Item menu. Doing so here, however, will result in unwieldy values.
You’d probably expect we need to establish proportional width and height constraints for our other two image buttons. In fact, we can set these to use the calculated dimensions for our center image button. For both left and right image buttons, control-drag to the middle button and select:
- Horizontal Spacing
- Vertical Centering (or Center Y)
- Equal Widths
- Equal Heights
(If you have any yellow frames after all this, try an Update Frames for All Views in View Controller via the Resolve Auto Layout Issues menu.)
Our image chooser view will now scale appropriately with device size.
Now let’s add the ability to close the image chooser and return to the main view. For as easy as it was to create a segue to open the image chooser, you’d think it’d be a simple matter to reverse direction and segue back. Unfortunately, it’s not. We will need to add a line of code to make it happen.
Unwinding
We mentioned in Part 1 that the main view controller has already been assigned a custom class of “ViewController,” which refers to the ViewController.swift file in the Project navigator. We’re going to break that relationship and replace it with our own.
First, select the Food Status view controller and switch to the Identity inspector (third icon in the right-hand pane). Under Custom Class: Class, delete the text “ViewController.” Then select the ViewController.swift file in the Project navigator and hit the delete key. Choose “Move to Trash” when Xcode asks what to do with the file. We’re going to create a new kind of controller, a “subclass” of the standard UIViewController, and add a little logic to it.
Select File > New > File. Choose iOS > Source > Cocoa Touch Class. Hit Next. Provide a class name of “FoodStatusViewController” and set it to be a subclass of UIViewController. Leave the language as Swift. Hit Next and save the new file in your project’s folder. Xcode will automatically select it in the Project navigator.
Xcode generates some boilerplate we won’t need. Delete everything between the first and last curly braces, so that all you’re left with is:
import UIKitclass FoodStatusViewController: UIViewController {}
(The lines above the import statement, prefixed by double backslashes, are code comments and have no effect at runtime.)
Now, after the first curly brace but before the second, insert the following code:
@IBAction func unwindToFoodStatusViewController(segue: UIStoryboardSegue) {
}
This is the “hook” our main view controller needs so other controllers can segue back to it. We can change “unwindToFoodStatusViewController” to any text we like, so long as it doesn’t include spaces or special characters; it’s just the name of the simple function we’ve added. However, it’s a good idea to keep “unwind” in the name since “unwinding” to the Food Status view controller is what we intend to do.
Hook It Up
At this point we are ready to complete the interface loop. Switch back to Main.storyboard and select the Food Status view controller. In the Identity inspector, change its Class to “FoodStatusViewController.” Now our “unwindToFoodStatusViewController” hook is available to the rest of the storyboard.
Select the Done button in the image chooser. Control-drag from the button to the red Exit icon at the top of the view controller. What we’re signifying is the Done button will exit the view. When you release the mouse button over the Exit icon, Xcode will present a popup with all available unwind segues. Since we’ve only added one so far, that’s all you’ll see. Select “unwindToFoodStatusViewController:.” Build the app to test your work.
You could also wire each of the image buttons to Exit > unwindToFoodStatusViewController:. The idea would be that tapping an image both selects it and dismisses the modal view.
endEditing
There’s one more quality-of-life touch we can add. If you run your app and click inside the text field, you’ll see the iOS software keyboard. (If it’s not visible, you can you can use Hardware > Keyboard > Toggle Software Keyboard to show or hide it with the text field in focus.) But you’ll find there’s no way for a user to dismiss it!
In many cases we’d replace the keyboard’s Return key with a Done key so the user could leave editing mode. But since this is a multiline text field, we kind of need a dedicated Return key. What we’d like to do is allow the user to tap outside the text field to dismiss the keyboard when done editing.
We can make this work with one more addition to FoodStatusViewController.swift. Select it in the Project navigator to see its code, and insert the following after the closing curly brace of our “unwindToFoodStatusViewController” function but before the final, closing curly brace of the subclass:
//hide keyboard
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
}
Now run the app one more time. You’ll find that clicking in the text field brings up the keyboard, but clicking in the area around the text field dismisses it again.
This syntax has unfortunately changed a bit with Xcode 7.1. You’ll need to use the following instead:
//hide keyboard
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
Our prototype has reached a good point. It’s adaptable for multiple devices, and it functions well. If you’d like to learn how to create something more energetic, stay tuned. In the last part of our prototyping series, we’ll roll in a third-party library so we can add some extra animation.
(You can download the example project file here. If you’re using Xcode 7.1, download this version instead.)