Working with Views and Storyboards
The most common part of every program’s user interface is a window that displays items such as buttons and text fields. In Xcode, windows are called views. In all but the simplest programs, a user interface will likely consist of two or more windows or views. That means your program needs to know how to open additional windows and close them again.
The two ways to create and store views are .xib files and .storyboard files. An .xib file holds one view so if you need to display multiple views, you’ll need to create multiple .xib files. A .storyboard file can hold one or more views.
You can create user interfaces with either .xib or .storyboard files, or a combination of both. Generally, .storyboard files are best for windows that logically link together. The biggest advantage of .storyboard files is that they link multiple views together in a logical sequence. The biggest disadvantage of .storyboard files is that if you have multiple views in your program, there may not be a logical sequence between displaying different views in a particular order. In that case, a .storyboard file can appear cluttered and be difficult to organize.
Whether you use .xib or .storyboard files is less important than knowing how to design a good user interface that makes performing tasks as easy as possible for the user.
Creating User Interface Files
When you create a project, Xcode gives you a choice between using storyboards or not as shown in Figure 14-1. If you choose not to use storyboards, then Xcode will create and store your user
interface in an .xib file. If you choose to use storyboards, then Xcode will store your user interface in a .storyboard file.
Figure 14-1. When creating an OS X project, Xcode gives you a choice of choosing storyboards or not
After you’ve created a project, you can always add additional .xib or .storyboard files no matter if you initially started with storyboards or not.
Adding an .xib or .storyboard File
To add an .xib or .storyboard file to a project, follow these steps:
Figure 14-2. Adding an .xib or .storyboard file to a project
If you create an .xib file using the above steps, you may still need to create a Swift file called a view controller to manage the view. To create a view controller Swift file and an .xib file at the same time, follow these steps:
Figure 14-3. Choosing Cocoa Class under the Source category
Figure 14-4. Defining a class name, subclass, and .xib file
Defining the Main User Interface
If your project only consists of a single .xib or .storyboard file, Xcode uses that one file as your program’s main user interface. However, if you have multiple user interface files (such as two .xib or .storyboard files, or a combination of both .xib and .storyboard files), you need to define which file should be your main user interface.
To define a main user interface file, follow these steps:
Figure 14-5. Choosing the main user interface for your project
Displaying Multiple .xib Files
If you have multiple .xib files in a project, you need to designate one .xib file as your main user interface. That means the other .xib files won’t be visible until you specifically make them appear. To open one .xib file from another one, there are three steps you need to take:
To see how to open and close an .xib file, follow these steps:
Figure 14-6. The Attributes Inspector pane lets you modify the appearance of a window
At this point, your program consists of a MainMenu.xib file that displays a single window with a push button on it. Now we need to create a view controller (containing Swift code) and an accompanying .xib file by following these steps:
Figure 14-7. Defining the features of a second. xib file and its view controller
At this point, you’ve created a second. xib file and an accompanying view controller file. Now it’s time to write Swift code to make everything work by following these steps:
Figure 14-8. Creating an IBAction method for the Open Window button
var windowController = secondView(windowNibName: "secondView")
@IBAction func openWindow(sender: NSButton) {
windowController.showWindow(sender)
}
@IBAction func closeWindow(sender: NSButton) {
self.close()
}
Figure 14-9. Running the XIBProgram
What you did was create a second .xib file with a view controller. Then you created an object in the AppDelegate.swift file called windowController, based on the secondView class that loads the secondView.xib file.
Inside the openWindow IBAction method, you used the showWindow method to open the .xib file stored in the windowController object, which is the secondView class.
When this second window appears, you clicked on the Back button, which ran the self.close() command that closed the window.
As you can see, opening and closing multiple .xib files requires Swift code. To make transitioning from one window to another easier, Xcode also offers storyboards.
Using Storyboards
Storyboards consist of two partsStoryboard:
You create scenes and place items on scenes such as buttons and text fields. Then you connect scenes using segues. By doing this, you can define how your user interface displays information on the screen.
To experiment with storyboards, you’ll need to create a project that uses storyboards by following these steps:
When you create a project that uses storyboards, you’ll see two boxes where one box represents your window or view (labeled Window Controller) and the second box represents that window’s contents (labeled View Controller in its title bar) as shown in Figure 14-10 . The second box (that has an arrow pointing to it) is where you can place additional user interface items such as buttons, text fields, and labels.
Figure 14-10. A view controller and view in a storyboard
You place items from the Object Library onto the bottom window (labeled View Controller). To add additional windows to a storyboard, you use the Object Library and drag different controller objects into your storyboard as shown in Figure 14-11.
Figure 14-11. Controllers you can add to a storyboard
Zooming In and Out of a Storyboard
When you click on a .storyboard file in the Project Navigator pane, Xcode displays your storyboard. The problem with storyboards is that they tend to consist of multiple scenes and segues, which you can’t easily see.
To help you see your entire storyboard or just a part of it, you can zoom magnification in and out. Xcode offers two ways to zoom in and out:
Figure 14-12. Right-clicking displays a magnification pop-up menu
The lower to zoom magnification, the more of the storyboard you’ll be able to see, so a zoom magnification of 25% displays more of the storyboard than a zoom magnification of 50%.
Note You’ll need to change the storyboard magnification to 100% when you want to place different items on the user interface such as buttons or text fields.
You can add scenes to a storyboard at any magnification. Lower magnifications (such as 25% or 50%) just make it easier to see how the individual scenes in your storyboard are connected. To place a new scene on a storyboard, follow these steps:
The five types of controllers you can place on a storyboard include:
You can think of a Window Controller as a window that contains a view. The view displayed inside the window is identified by an arrow pointing from the Window Controller to the view as shown in Figure 14-13.
Figure 14-13. A Window Controller contains a single view
On the other hand, a Vertical/Horizontal Split View Controller acts like a window that holds two views either side by side or stacked on top of each other as shown in Figure 14-14.
Figure 14-14. A Split View Controller contains two views
The Tab View Controller also consists of a single window that can contain two or more views. The difference is that it can display tabs where each tab represents a different view as shown in Figure 14-15. You can also add more than two views to a Tab View Controller.
Figure 14-15. A Tab View Controller displays two or more views in one window identified by tabs
Defining the Initial Scene in a Storyboard
In every storyboard, one scene must be designated as the initial scene, which is the first window or view that appears when your program runs. Xcode identifies the initial scene with an arrow pointing to the right.
Another way to identify the initial scene is to click on the blue icon in the top middle part of the controller and open the Show Attributes Inspector pane. If the “Is Initial Controller” check box is selected, then the currently selected window is the initial scene as shown in Figure 14-16.
Figure 14-16. An arrow and the “Is Initial Controller” check box identifies the initial scene
To change the initial scene, you can do one of the following:
Note: There can only be one initial scene at a time.
When a storyboard consists or two or more scenes, you need a way to display those other scenes. First, you need a way to switch from one scene to another. Second, you need a way to go back. Third, you may need to pass data from one scene to another.
Moving from one scene to another involves creating a segue between scenes. To create a segue between scenes, follow these steps:
Figure 14-17. Control-dragging the mouse from a button to another scene creates a segue
Figure 14-18. A pop-up menu lets you define how to display the scene
Figure 14-19. Clicking on a segue lets you edit its attributes and identify the user interface item that runs that segue
Displaying Scenes From a Segue
A segue not only connects one scene to another scene, but also defines how that second scene appears. The five different ways a scene can appear include:
When you first create a segue, you can define how the segue should display the scene. However, you can always change this by following these steps:
Removing a Scene After a Segue
A segue works in one direction from one scene to a second scene. When you create a second scene using the Modal, Sheet, Popover, or Custom segue, you can close this second scene using Swift code. To do this, you need to create a Swift controller file for your scene. Then connect a user interface item from that scene (such as a button) to define an IBAction method where you can use Swift code to close a scene.
If you open a scene using a Show segue, then the user can close the scene by clicking the close button, which doesn’t require you to write any Swift code at all.
To remove a scene after a Modal, Sheet, Popover, or Custom segue, follow these steps:
Figure 14-20. Creating a Swift class to control a scene in a storyboard
Figure 14-21. Connecting a scene to a Swift view controller file
@IBAction func closeScene(sender: NSButton) {
self.dismissController(self)
}
When you make changes on one scene and then open another scene, you may want that second scene to know of any changes you made earlier on the previous scene. To do this, you need to do the following:
To see how to pass data from one scene to another, follow these steps:
Figure 14-22. The user interface of the initial scene
@IBOutlet weak var passedText: NSTextField!
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var passedText: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prepareForSegue(segue: NSStoryboardSegue, sender: AnyObject?) {
let secondScene = segue.destinationController as! secondView
secondScene.representedObject = passedText.stringValue
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
The passedText IBOutlet retrieves the text that the user types into the text field. Then the prepareForSegue method creates a constant called “secondScene” that represents the segue’s destination, which is the secondView class. Then it takes the text from the passedText IBOutlet and stores it into the representedObject property.
Figure 14-23. The user interface of the second scene
@IBOutlet weak var receivedText: NSTextField!
import Cocoa
class secondView: NSViewController {
@IBOutlet weak var receivedText: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
receivedText.stringValue = self.representedObject! as! String
}
@IBAction func closeScene(sender: NSButton) {
self.dismissController(self)
}
}
The receivedText IBOutlet displays the text that appears in the label. Then the viewDidLoad method takes the representedObject property, casts or turns it into a String data type, and stores this into the receivedText IBOutlet.
Summary
You create your user interface and store them in multiple .xib files or a single .storyboard file that contains multiple scenes. To open and close different .xib files, you have to write Swift code. To open a scene in a storyboard, you just need to Control-drag from a button on one scene to another scene.
To make a second scene close after opening it, you have to write Swift code. You also need to use Swift code to transfer data from one scene to another. When you transfer data from one scene to another, you use the representedObject property. To access any value in the representedObject property, you must unwrap it and cast or turn it into a specific data type.
Storyboards let you define the order that scenes appear that make up your program’s user interface. To make it easy to see your entire storyboard, you can adjust the magnification to shrink or enlarge the storyboard. However when you want to place items on a storyboard scene, you must enlarge the magnification to 100%.
When you add additional scenes in a storyboard, you’ll need to create Swift files that control those scenes. These Swift files need to be of the NSViewController class, and then you must connect your scene to that Swift file.
Designing your program’s user interface involves using .xib or .storyboard files, or a combination of both. Storyboards reduce the need to write Swift code, but with both types of files, you’ll still need to write Swift code to make your user interface work completely.