• Tutorial Storyboards in iOS 9

    07 June 2017

     Storyboards are an exciting feature first introduced way back in iOS 5 that save you a lot of time building user interfaces for your apps.

    To show you what a storyboard is, I’ll let a picture do the talking. This is the storyboard that you will be building in this tutorial:

    You may not know exactly yet what the app does but you can clearly see which scenes it has and how they are related.

    Storyboards have a number of advantages:

    • You can visually lay out all your view controllers in “scenes” and describe the connections between them. With a storyboard you have a better conceptual overview of all the scenes in your app.
    • Storyboards can describe the transitions between the various scenes. These transitions are called “segues” and you create them by connecting your view controllers right in the storyboard. Thanks to segues you need less code to take care of your UI.
    • Storyboards make working with table views a lot easier with prototype cells and static cells features. You can design your table views almost completely in the storyboard editor, cutting down on the amount of code you have to write.
    • Storyboards make it easier to use Auto Layout, a feature that allows you to define mathematical relationships between elements that define their position and sizing. This powerful feature makes it much easier to handle devices of varying screen sizes and dimensions. In this tutorial you will use Auto Layout a little, but it is outside the scope of this tutorial. You can read more about it in our Auto Layout Tutorial or watch the video series.

    In this storyboards tutorial you’re going to build a simple app that lets you create a list of players and games, and rate their skill levels. In the process, you’ll learn the most common tasks that you’ll be using in storyboards.

    Getting Started

    Fire up Xcode and create a new project. Use the Single View Application template as the starting point.

    Fill in the template options as follows:

    • Product Name: Ratings
    • Organization Name: fill this in however you like
    • Organization Identifier: the identifier that you use for your apps
    • Language: Swift
    • Devices: iPhone
    • Use Core Data: not checked
    • Include Unit Tests and UI Tests: not checked

    After Xcode has created the project, the main Xcode window looks like this:

    The new project consists of two classes, AppDelegate and ViewController, and the star of this tutorial: theMain.storyboard file.

    This is a portrait-only app, so before you continue, uncheck the Landscape Left and Landscape Rightoptions under Deployment Info > Device Orientation seen in the General project settings shown above .

    Let’s take a look at that storyboard. Click Main.storyboard in the project navigator to open it in theInterface Builder editor:

    The official storyboard terminology for a view controller is “scene”, but you can use the terms interchangeably. The scene is what represents a view controller in the storyboard.

    Here you see a single view controller containing an empty view. The arrow pointing at the view controller from the left indicates that it is the initial view controller to be displayed for this storyboard.

    Designing a layout in the storyboard editor is done by dragging controls from the Object Library (see bottom-right corner) into your view controller. You’ll see how easy that is in just a moment.

    Note: You’ll notice that the default scene size is a square. Xcode 7 enables Auto Layout and Size Classes by default for storyboards. Auto Layout and Size Classes allow you to make flexible user interfaces that can easily resize, which is useful for supporting the various sizes of iPhones and iPads. To learn more about size classes, check out our Adaptive Layout video tutorial series.

    In this tutorial you will take the optional step of resizing the scenes in your storyboard so that you can more easily visualise what the final screen will look like.

    Before you get to exploring, resize the scene to simulate an iPhone 6/6s.

    Select View Controller in the Document Outline. If you don’t see a Document Outline, click this button at the bottom left of the storyboard canvas:

    In the Attributes Inspector under Simulated Metrics, change Size to iPhone 4.7 inch

    The scene in the storyboard will now show as the size of the iPhone 6 or 6s, which are 4.7 inch iPhones.

    “Inferred” is the default setting for Simulated Metrics in storyboards. Simulated Metrics are a visual design aid inside the storyboard that shows what your screen will end up looking like. Just remember that they aren’t used during runtime.

    To get a feel for how the storyboard editor works, drag some controls from the Object Library in the lower right into the blank view controller:

    As you drag the controls in, they should show up on the Document Outline on the left:

    The storyboard shows the contents of all your view controllers. Currently there is only one view controller (or scene) in your storyboard, but over the course of this tutorial you’ll be adding several others.

    There is a miniature version of this Document Outline above the scene called the Dock:

    The Dock shows the top-level objects in the scene. Each scene has at least a View Controller object, a First Responder object, and an Exit item, but it can potentially have other top-level objects as well. The Dock is convenient for making connections to outlets and actions. If you need to connect something to the view controller, you can simply drag to its icon in the Dock.

    Note: You probably won’t be using the First Responder very much. This is a proxy object that refers to whatever object has first responder status at any given time. As an example, you can hook up the Touch Up Inside event from a button to First Responder’s cut: selector. If at some point a text field has input focus then you can press that button to make the text field, which is now the first responder, cut its text to the pasteboard.

    Run the app and it should look exactly like what you designed in the editor (yours may look different than the screenshot below – this is just for demonstration and will not be used later in the tutorial):

    The single View Controller you defined was set as the Initial View Controller – but how did the app load it? Take a peek at the application delegate to find the answer. Open up AppDelegate.swift and you’ll see the source starts with this:

    import UIKit
     
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
     
      var window: UIWindow?
     
      func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        return true
      }

    The @UIApplicationMain attribute at the top of the file designates the AppDelegate class as the entry point for the module. It is a requirement for using storyboards that your application delegate inherits fromUIResponder and that it has a UIWindow property. All the methods are practically empty. Evenapplication(_:didFinishLaunchingWithOptions:) simply returns true.

    The secret is in the Info.plist file. Click on Info.plist in the Project Navigator and you’ll see this:

    Storyboard apps use the key UIMainStoryboardFile, also known as “Main storyboard file base name”, to specify the name of the storyboard that must be loaded when the app starts. When this setting is present,UIApplication will load the named storyboard file, automatically instantiate the “Initial View Controller” from that storyboard, and then put that controller’s view into a new UIWindow object.

    You can also see this in the Project Settings under the General tab and Deployment Info section:

    Now to create the real Ratings app with several view controllers.

    Just Add It To My Tab

    The Ratings app you’re about to build has a tabbed interface with two screens. With a storyboard it is really easy to create tabs.

    You’ll want to start with a clean storyboard, so switch back to Main.storyboard and delete the view controller you worked with earlier. This can be done by clicking on View Controller in the Document Outline and pressing the Delete key.

    Drag a Tab Bar Controller from the Object Library into the canvas. You may want to maximize your Xcode window first, because the Tab Bar Controller comes with two view controllers attached and you’ll need some room to maneuver. You can zoom in and out by double-clicking the canvas, or you can set the zoom scale by ctrl-clicking the canvas and selecting the zoom level.

    For convenience, again change the Simulated Metrics to show the scene as an iPhone. As you did before, select Tab Bar Controller in the Document Outline, and on the Attributes Inspector, change Size toiPhone 4.7 inch. This will also change the two embedded view controllers to simulate the iPhone 6 or 6s in the storyboard.

    The new Tab Bar Controller comes pre-configured with two additional view controllers – one for each tab. UITabBarController is a so-called container view controller because it contains one or more other view controllers. Two other common containers are the Navigation Controller and the Split View Controller (you’ll use the Navigation Controller later).

    The container Relationship is represented by the arrows between the Tab Bar Controller and the view controllers that it contains. An embed Relationship in particular is signified by the icon seen below in the middle of the arrow body.

    Note: If you want to move the Tab Bar Controller and its attached view controllers as a group, zoom out, and then you can ⌘-click or click and drag to select multiple scenes. This makes it possible to move them around together. (Selected scenes have a thin blue outline.)

    Drag a label into the first view controller (currently titled “Item 1”), double click it, and give it the text “First Tab”. Also drag a label into the second view controller (“Item 2”) and give it the text “Second Tab”. This allows you to actually see something happen when you switch between the tabs.

    Note: You can’t drag stuff into the scenes when the editor is zoomed out. You’ll need to return to the normal zoom level first by double-clicking in the canvas.

    Build & Run, and you’ll see something similar to this in the console:
    Ratings[18955:1293100] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?

    Fortunately, the error is pretty clear here – you never set an entry point, meaning you didn’t set the Initial View Controller after you deleted the scene used earlier. To fix this, select the Tab Bar Controller and go to the Attributes Inspector. Check the box that says Is Initial View Controller.

    In the canvas, the arrow that used to point to the deleted view controller now points at the Tab Bar Controller:

    This means that when you run the app, UIApplication will make the Tab Bar Controller the main screen. Run the app and try it out. The app now has a tab bar and you can switch between the two view controllers with the tabs:

    Tip: To change the initial view controller, you can also drag the arrow between view controllers.

    Xcode actually comes with a template for building a tabbed app (unsurprisingly called the Tabbed Application template) that you could have used, but it’s good to know how this works so you can also create a Tab Bar Controller by hand if you have to.

    Note: If you connect more than five scenes to the Tab Bar Controller, it automatically gets a More… tab when you run the app. Pretty neat!

    Adding a Table View Controller

    The two scenes that are currently attached to the Tab Bar Controller are both regular UIViewControllerinstances. You are going to replace the scene from the first tab with a UITableViewController instead.

    Click on that first view controller in the Document Outline to select it, and then delete it. From the Object Library drag a new Table View Controller into the canvas in the place where that previous scene used to be:

    Now you want to place the Table View Controller inside a navigation controller. With the Table View Controller selected, choose Editor\Embed In\Navigation Controller from Xcode’s menubar. This adds yet another controller to the canvas:

    You could also have dragged in a Navigation Controller from the Object Library and embedded the tableview, but this Embed In command is a nice time saver for a common action.

    Because the Navigation Controller is also a container view controller (just like the Tab Bar Controller), it has a relationship arrow pointing at the Table View Controller. You can also see these relationships in the Document Outline:

    Notice that embedding the Table View Controller gave it a navigation bar. Interface Builder automatically put it there because this scene will now be displayed inside the Navigation Controller’s frame. It’s not a realUINavigationBar object, but a simulated one. Simulated Metrics will infer the context around the scene and show a navigation bar when it’s inside a Navigation Controller, a tab bar when it’s inside a Tab Bar Controller, and so on.

    The new controllers are currently square shaped. When you embed them inside the Tab Bar Controller as you will in a moment, they will change their simulated size to match the parent scenes.

    To connect these two new scenes to the Tab Bar Controller, ctrl-drag from the Tab Bar Controller to the Navigation Controller. When you let go, a small popup menu appears. Choose the Relationship Segue – view controllers option:

    This creates a new relationship arrow between the two scenes. This is also an embed Relationship as you saw with the other controllers contained by the Tab Bar Controller.

    The Tab Bar Controller has two embed relationships, one for each tab. The Navigation Controller itself has an embed Relationship with the Table View Controller.

    When you made this new connection, a new tab was added to the Tab Bar Controller, simply named “Item”. For this app, you want this new scene to be the first tab, so drag the tabs around to change their order:

    Run the app and try it out. The first tab now contains a table view inside a navigation controller.

    Before you put some actual functionality into this app, you need to clean up the storyboard a little. You will name the first tab “Players” and the second “Gestures”. You don’t change this on the Tab Bar Controller itself, but in the view controllers that are connected to these tabs.

    As soon as you connect a view controller to a Tab Bar Controller, it is given a Tab Bar Item object which you can see in the Document Outline or the bottom of the scene. You use this Tab Bar Item to configure the tab’s title and image seen on the Tab Bar Controller.

    Select the Tab Bar Item inside the Navigation Controller, and in the Attributes inspector set its Title toPlayers:

    Rename the Tab Bar Item for the view controller from the second tab to Gestures in the same manner.

    A well-designed app should also put some pictures on these tabs. The resources for this tutorial contains a subfolder named Images. Drag that folder into the Assets.xcassets subfolder in the project.

    Back in Main.storyboard, in the Attributes inspector for the Players Tab Bar Item, choose thePlayers.png image.

    You probably guessed it, but give the Gestures item the image Gestures.png.

    A view controller that is embedded inside a Navigation Controller has a Navigation Item that is used to configure the navigation bar. Select the Navigation Item for the Table View Controller in the Document Outline and change its title in the Attributes inspector to Players. .

    Notice that the Scene title in the Document Outline now changes to Players

    Alternatively, you can double-click the navigation bar and change the title there. Note that you should double-click the simulated navigation bar in the Table View Controller, not the actual Navigation Bar object in the Navigation Controller.

    Run the app and marvel at your pretty tab bar, created without writing a single line of code!

    Prototype Cells

    Prototype cells allow you to easily design a custom layout for your table view cells directly from within the storyboard editor.

    The Table View Controller comes with a blank prototype cell. Click on that cell to select it and in theAttributes inspector set the Style option to Subtitle. This immediately changes the appearance of the cell to include two labels.

    With so much stackable content on a storyboard, it can sometimes be difficult to click on exactly what you want. If you have trouble, there are several options. One is that you can select the item in the Document Outline to the left of the canvas. The second is a handy hotkey: hold control + shift and click on the area you’re interested in. A popup will appear allowing you to select any element directly under your cursor.

    If you’ve used table views before and created your own cells by hand, you may recognize this as theUITableViewCellStyle.Subtitle style. With prototype cells you can either pick one of the built-in cell styles as you just did, or create your own custom design (which you’ll do shortly).

    Set the Accessory attribute to Disclosure Indicator and in the Identifier field type PlayerCell. All prototype cells should have a reuse identifier so that you can refer to them in code.

    Run the app, and… nothing has changed. That’s not so strange: you still have to make a data source for the table so it will know what rows to display. That’s exactly what you’re going to do next.

    Add a new file to the project. Choose the Cocoa Touch Class template under iOS/Source. Name the classPlayersViewController and make it a subclass of UITableViewController. Uncheck Also create XIB file. Choose the Swift language and hit Next followed by Create.

    Go back to the storyboard and select the Table View Controller (make sure you select the actual view controller and not one of the views inside it). In the Identity inspector, set its Class toPlayersViewController. That is the essential step for hooking up a scene from the storyboard with your custom view controller subclass. Don’t forget this or your class won’t be used!

    From now on when you run the app that table view controller from the storyboard is an instance of thePlayersViewController class.

    The table view should display a list of players, so now you will create the main data model for the app – an array that contains Player objects. Add a new file to the project using the Swift File template under iOS/Source. Name the file Player.

    Replace the code in Player.swift with:

    import UIKit
     
    struct Player {
      var name: String?
      var game: String?
      var rating: Int
     
      init(name: String?, game: String?, rating: Int) {
        self.name = name
        self.game = game
        self.rating = rating
      }
    }

    There’s nothing special going on here. Player is simply a container object for these three properties: the name of the player, the game they’re playing, and a rating of 1 to 5 stars.

    You’ll next make an array of test Player objects and then assign it to an array in PlayersViewController. Start by creating a new file using the Swift File template named SampleData. Add this to the end ofSampleData.swift:

    //Set up sample data
     
    let playersData = [ 
      Player(name:"Bill Evans", game:"Tic-Tac-Toe", rating: 4),
      Player(name: "Oscar Peterson", game: "Spin the Bottle", rating: 5),
      Player(name: "Dave Brubeck", game: "Texas Hold 'em Poker", rating: 2) ]

    Here you’ve defined a constant called playersData and assigned an array of hard coded Player objects to it.

    Now add a Player array property just below class PlayersTableViewController: UITableViewControllerin PlayersViewController.swift to hold the list of players:

    var players:[Player] = playersData

    You could simply have set up the sample data in PlayersViewController when defining the playersvariable. But because this data might later be provided from a plist or an SQL file, it’s wise to handle loading the data outside of the view controller.

    Now that you have an array full of Player objects, you can continue hooking up the data source inPlayersViewController. Still in PlayersViewController.swift, replace the table view data source methods with the following:

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
      return 1
    }
     
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return players.count
    }

    The real work happens in cellForRowAtIndexPath. Replace this method, which is currently commented out, with:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
     -> UITableViewCell {
      let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)
     
      let player = players[indexPath.row] as Player
      cell.textLabel?.text = player.name
      cell.detailTextLabel?.text = player.game
      return cell
    }

    The method dequeueReusableCellWithIdentifier(_:forIndexPath:) will check to see if there is an existing cell that can be recycled. If not, it will automatically allocate a prototype cell and return it to you. All you need to do is supply the re-use identifier that you set on the prototype cell in the storyboard editor – in this case PlayerCell. Don’t forget to set that identifier, or this little scheme won’t work!

    Run the app, and lo and behold, the table view has players in it!

    It takes just a few lines of code to use these prototype cells. I think that’s just great!

    Note: In this app you’re using only one prototype cell but if your table needs to display different kinds of cells then you can simply add additional prototype cells to the storyboard. You can either duplicate the existing cell to make a new one, or increment the value of the Table View’s Prototype Cells attribute. Be sure to give each cell its own re-use identifier, though.



Comments

Comments closed on this post.