The Simulator for WatchKit is the worst part of Xcode. It’s horribly buggy, and has one particular bug that freezes or kills your running app very often. I had a hard time figuring this out, but once I found one place that discussed it, the number of people with the same issue surprised me. Apparently if something is wrong in your layout on a single interface app, the app fails and hangs. There is a solution: Use more than one interface scene, then run your app. This get us into the world of the three type of controllers you can use in WatchKit apps: hierarchical, Page-based and modal. Unlike iOS, you can’t use all three in your app. You have to choose for your app to be completely Hierarchical or Page-based, no mixing allowed. You are however allowed to use modals with both.
Page-Based Controllers
The easiest of the controllers is the page-based interface. Page interfaces are swiped from one view to another like their iOS counterpart:
Page views have difficulty not communicating information between views. They are for related views that do little to no communication with each other.
Unlike the iOS equivalent, which requires delegates and several views, they are very easy to set up. Let’s set up an example. In XCode, start a new single-view project named SwiftWatchPageDemo, with Universal as the device and Swift as the language. Once loaded in the drop down menu select Editor>Add Target.
Select an Apple Watch WatchKit App for this application.
We will not use notifications. In the next window, make sure both glances and notifications are checked off.
Click Finish and then Activate. In the navigator, find the Watchkit App group. Open the Interface.storyboard.
You will have an empty storyboard with one controller. In the object inspector, find the Interface controller, which should be at the top of the list.
Drag three interface controllers to the storyboard, placing them next to each other like this:
Drag one label to each of the interfaces. Position them Center Vertically and Center Horizontally. Change the text in the label to match the screenshot.
On the interface labeled One, click where the interface says interface. You will see the interface controller icon.
Control-Drag from the controller icon to the interface labeled Two until it highlights.
Release the mouse button and you will get a very short menu of segue options.
Select next page, and we get the page segue:
Repeat the process to link interface Two to Three, and Three to Four to get this:
That’s all you need to do. Build and run. Swipe the watch screen and you change pages:
Instead of segues, We can transition programmatically. Quit the simulator, and back in the storyboard delete the segues, but leave the controllers in place. Click on the view controller icon for the One interface, and in the attribute inspector find the Identifier. Change it to One. Incidentally you can give your pages titles. In the title field, add First Controller.
Do the same for the Two interface. so it looks like this:
Then do the same for the Three/Third and Four/Fourth controller.
When done, add another interface to the left of the others.
In the attributes inspector for this new interface change to this:
WatchKit has no AppDelegate
for initialization. We have to simulate one by making an initialization controller to load the pages. Press Command-N and create a new file named MainInterfaceController subclassing WKInterfaceController. When the file finishes saving, change the awakeWithContext
method to this:
override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) // Configure interface objects here. WKInterfaceController.reloadRootControllersWithNames(["One","Two","Three","Four"],contexts: nil) }
The class method reloadRootControllersWithNames
loads the pages.The first parameter takes an array of interface identifiers represented as strings. The order is significant. The first element will be the first page displayed and so on.
Go back to the storyboard. Select the main controller, and in the Identity inspector, change its class to MainInterfaceController.
Build and run. Once again we get pages we can swipe through.
Pages require swiping, and give you little choice of which page to go to next. You could get complicated and change the order of pages with reloadRootControllersWithNames
in a button’s code and several re-arranged arrays. But that is messy and complicated. There is an easier way which handles data better: Hierarchical interfaces. In our next lesson, we’ll look at these interfaces.
Leave a Reply