Welcome to the third installment in our series on how to both design and build a 1980s version of the iOS "Phone" app. In this tutorial we will be jumping into both Xcode and Interface Builder to setup the basic view hierarchy of our application and deconstruct the app design into individual iOS SDK components.
Final App Preview
This is a snapshot of what we will be building over the course of this series:
Before You Begin. . .
This is a multi-part series designed to teach intermediate iOS SDK topics. The content will become increasingly complex as the series progresses. If at any point you find yourself lost in following this series, you might need to take a step back and work your way through our Learn Objective-C series or our Beginning iOS SDK Development series.
Step 1: Create a New Tab Bar Application
Open Xcode and create a new project. A quick look at the design comp reveals that all of our views are presented with a
UITabBar, so select the "Tab Bar Application" template:
Feel free to name the project whatever you would like, but this series will be using the title "PhoneAppSkin":
In the "Groups & Files" Xcode pane open the "Resources" group and double-click the file
MainWindow.xib. As you can see, selecting the "Tab Bar Application" template has created an application with two tabs loaded from the
SecondView.xib files respectively.
We will be customizing this default implementation to meet the needs of our application next.
Step 2: Create the Contacts Tab View
Working left-to-right, the first tab in our application is for the "Contacts" view. Let's start the configuration of our Tab Bar by creating a
UIViewController subclass just for this view.
Switch back to Xcode and locate the "Classes" group in the "Groups & Files" pane. Right click the group and select Add > New File:
Select "UIViewController subclass" from the available file templates and check the "With XIB for user interface" option:
Name the file
ContactsViewController and click "Finish".
Rename the file
ContactsView.xib and drag it from the "Classes" group and into the "Resources" group.
Next, double-click the
ContactsView.xib file to open it in Interface Builder.
A quick look back at our design comp for this view shows that it is composed of a navigation bar at the top, our tab bar controller at the bottom, and a UITableView with our various contacts in the middle.
The tab bar controller has already been created for us, and we will create the navigation controller momentarily. So, for now, we'll just add a table view as a subview of the contacts view.
If it isn't already displayed, open the Library window in Interface Builder by selecting Tools > Library from the application menu. Type
UITableView into the search box, and then drag the UITableView object from the Library window onto the contacts view:
Size the view controller to fill the contacts view:
With our contacts view controller created, it's time to integrate it into our tab bar controller. To do so, we are actually going to embed it as the root view controller of a
UINavigationController object, and then place that
UINavigationController into the first
Save your changes and switch back to the
MainWindow.xib file in Interface Builder. From the Library window, type
UINavigationController into the search box. Drag an instance of the navigation controller object onto the tab bar displayed in the Window view:
You can see that the tab bar is now displaying a navigation bar with the title "Root View Controller" at the top. Our next step is to set the root view controller of the
UINavigationController object to the contacts view controller we created earlier. To do this, expand the navigation controller object in
MainWindow.xib, select the child View Controller object, and then inspect the properties of this view controller by selecting Tools > Inspector from the Interface Builder menu bar. After doing so, your screen should look something like this:
Select the "Identity" tab in the inspector and set the class name to
Next, in the "Attributes" tab in the inspector, set the title to "Contacts" and the NIB name to "ContactsView":
Finally, in the
MainWindow.xib organizer, select the
UINavigationItem labeled "Navigation Item (Contacts)". In the "Attributes" tab of the inspector window for this object, set the title to "Contacts":
At this point, there is just one more configuration that we need to make to have the basic Contacts view structure setup. Double-click the text "Item" in the tab bar we added with the navigation controller object, and change the text to "Contacts" to match the design comp:
Save your work in Interface Builder and build and run your project in Xcode. If all went well, your app should now look something like this in the simulator:
With this initial groundwork in place for the Contacts tab view, we're ready to move on to setting up the Phone tab view.
Step 3: Create the Phone Tab View
In Xcode, follow the process described in Step 2 to add another custom
UIViewController to the "Classes" group. This time name the controller PhoneViewController, and rename the
PhoneViewController.xib file to
PhoneView.xib before dragging it into the "Resources" group with the other XIB files.
PhoneView.xib file to open it in Interface Builder. Drag a
UILabel object from the Interface Builder Library window onto the view. Enter the text "Phone View" into the label:
Switch back to the
MainWindow.xib file in Interface Builder. In the Library window, search for
UIViewController and drag a view controller object onto the tab bar, just after our "Contacts" tab and just before the tab titled "First".
Rename the tab caption to "Telephone" to match our design comp:
Like before, you'll need to expand the tab bar controller object in the
MainWindow.xib organizer and find the new view controller you just added onto the tab bar; it should be labeled "Selected View Controller (Telephone)". In the attributes tab of the Inspector window for this object, set the title field to "Telephone" and the NIB name field to "PhoneView":
Jump over to the "Identity" tab in the Inspector. Set the class for this object to "PhoneViewController":
Before you save your work in Interface Builder and test your changes, let's go ahead and ditch the extra, default "First" and "Second" tabs in the tab bar. To do so, simply drag them off of the tab bar controller and into oblivion:
Save your work in Interface Builder and switch back to Xcode.
In the "Classes" group, find the files
FirstViewController.m. Right click on these files and select "Delete". When prompted, choose the "Also Move to Trash" option. Do the same for the
SecondView.xib files in the "Resources" folder.
Save your work and build and run your project in the simulator again. It should now look like this:
Step 4: Create the Settings Tab View
The process of creating the settings tab is going to follow the same pattern used in Step 3. You might think that it would follow the process in Step 2, as you can see what looks like a custom navigation bar in the design comp.
However, the settings tab view isn't part of a more complex view hierarchy that will need to have additional views pushed or popped from the screen like in the Contacts tab, so using a navigation controller object is unnecessary. Instead, we can just use a
UIImageViewfor the custom background and a
UILabelfor the text.
In Xcode, follow the pattern established in both steps 2 & 3 to add a new
UIViewController subclass file to the classes folder. Name the class "SettingsViewController" and rename the XIB file to "SettingsView" before dragging the XIB into the "Resources" group.
SettingsView.xib in Interface Builder and add a single
UILabel to the center of the view. Set the label text to "Settings View".
Now switch back to the
MainWindow.xib file in Interface Builder, and follow the process from step 3 to add a new view controller object tab. Set the tab caption to "Settings" to match our design comp, and in the attributes tab of the Inspector window for the new view controller set the NIB name field value to "SettingsView" and the title field value to "Settings". In the identity tab of the Inspector window, set the class to "SettingsViewController".
Save your work in Interface Builder and build and run your application again. If all went well, you should now be able to flip through the screens below:
Step 5: Draft a Graphic Request Form
With the help of Interface Builder, we've been able to very quickly setup a basic view hierarchy to match the design comp created by Callum Chapman in parts 1 & 2 of this series. Of course, all of the objects we are using still need to be customized, and for that we will create a Graphic Request Form to send back to Callum, who will then splice his PSD file into the individual graphic files we need to proceed with skinning the interface.
If you are especially adventurous and will be working through all tutorials in this series, then consider this the form I'm sending to you for splicing! :)
In order to determine the graphics necessary for our app and request them from Callum, we'll first need to deconstruct the final design preview created by Callum into individual objects and then map out a strategy to theme each one.
Default Graphic Resources
In all new iOS projects, there are a few resources such as the app icon that are always needed. Let's start by listing those needs:
- App Icon
The app icon is the logo that our users will tap to launch the application. On non-retina displays, this icon should be 57x57 pixels in size, but on retina screens it should be 114x114 pixels in size. It should be provided in PNG format.
- Loading Screen
As the name implies, the loading screen of the application is what will display immediately after the user taps our app icon as our application loads into memory. Because it will fill the entire screen, it should match the size of the iPhone display, namely 320x480 pixels for standard screens and 640x960 pixels for retina display screens. As with the vast majority of iOS graphic resources, the loading screen should be provided in PNG format.
App-Wide Graphic Resources
Now that we have defined the items that are necessary for all iOS apps, let's think about the app-wide resources necessary for just our application.
Because our entire app is based on a
UITabBarController view hierarchy, the tab bar will be present on all screens in the application (with the exception of perhaps any special modal views displayed). Apple provides a set of
UITabBarItem icons with the SDK, but none of the icons used by Callum are from this default
Consequently, we will need the following custom
- Contacts Icon
- Telephone Icon
- Settings Icon
All of the above icons will need to be provided in two different states: a default (not selected) state and a highlighted (selected) state. We could create the highlighted state programmatically, but I prefer to have a bitmap highlighted state image available as an alternative option when starting a project. The size of these images should be 30x30 pixels with a 60x60 pixel version supplied for retina displays. They should be in PNG format.
In addition to the custom tab bar icons, do you notice the single red line just above the tab bar background? We'll need a custom tab bar background that includes that detail. The image should be in PNG format and will need to span a width of 320 pixels for standard screens and 640 pixels for retina screens. However, rather than asking for images with those dimensions, we can just ask for a linear gradient capable of spanning either dynamically.
Finally, the navigation controller background is common to both the contacts and settings tab views, and we may need to include it in other modal views in the application as well.
Let's tack on the custom
UINavigationController background (complete with the red line at the top) into our app-wide graphic needs. This image should be in PNG format, and, like our tab bar background, must be capable of spanning the width of both standard and retina displays. Judging from the design comp, it looks like this can also be provided as a linear gradient that could span any width necessary.
Contacts Tab Resources
A look at this screen reveals only one non-standard UI element: a custom detail disclosure button to be displayed on each
The rest of the theme for this screen can be handled with the default
Phone Tab Resources
For the phone tab, we can deconstruct the interface into three basic objects: a
UIImageView for the background image,
UIButton objects for the numbers 0 - 9, the "del" and "dial" buttons, and either a
UILabel for the number display or a series of
UIImage objects joined together, depending on whether or not we can include the font used for the dial display in our project. If the font is either shipped with iOS or available freely with a creative-commons license, then we can use a
UILabel, otherwise Callum will need to provide individual PNG images for each number.
For all of the
UIButton objects on this screen, we will need an unpressed and a pressed state, however, we should be able to just use a
UILabel for the actual number displayed on top of the button background, meaning we really only need one standard
UIButton background for the unpressed state and one standard
UIButton background for the pressed state. For the "del" and "dial" buttons, we should also have a disabled state. All of these resources should be provided in PNG format with versions for standard and retina screen types.
It's worth mentioning that if our
UIButtonbackground consisted of purely a simple linear or radial gradient, it would be simple to draw them dynamically with code. However, as the pattern used is more complex, it's not worth taking the time to programmatically draw these backgrounds when they are already readily available in bitmap format.
Settings Tab Resources
Finally we come to the settings tab view. For this screen we really just need several
UIImage objects for the background behind the "Preset Themes", "Background Color", etc. headings and a number of
UIButton objects for each theme selection option in both a default and selected state.
The real question presented by this screen is how to handle theme selection. One option would be to custom draw all of the graphic resources in the project and simply alter the options provided to our drawing methods when the user selects a different variation. I like this approach in theory, but, in practice, I think the complexity of many of the design elements means that it would be impractical to do so. Therefore, for all of the bitmap images already pointed out above, we will need to request custom bitmap variations for each theme possibility. As we will see later in this series, there are still some UI elements that we will customize in code, such as the
UILabel font color and the
UIView background color.
Creating the Request Form
Now that we have a grasp on what graphic resources will be needed in order to customize our project, we're ready to compile them all together into a request form for splicing. Using an invoicing template in Pages as my base, I quickly put together the following:
The Pages version of this template is attached in the download with this post.
Use something similar in your own projects? Post a link in the comments below as requesting spliced graphics is a very common task!
Of course, I wouldn't suggest simply sending a form like this to a designer or design team without some explanation. Ideally you can setup a call with the designer on your project and walk them through each of these points, answering questions as they arise.
In this tutorial, we setup a basic view hierarchy for our application with Interface Builder and deconstructed the app design into individual components suitable for splicing into PNG files.
Next Time. . .
The next tutorial in this series will feature Callum Chapman demonstrating how to take the Graphic Request Form created in this tutorial and splice out the files necessary for the app development and theming process to continue. Further installments in this tutorial series will delve into customizing the
UITabBarController, and other objects, as well as how to browse the user's address book information and dial phone numbers from within your app.
If you enjoyed this tutorial and would like to see further content from Mobiletuts+, be sure to subscribe via RSS, follow us on Twitter, or join our Facebook fan page to get all the latest updates on our content!