A WatchKit Glance Tutorial

Revision as of 16:20, 8 May 2015 by Neil (Talk | contribs) (About the Glance Scene)

Revision as of 16:20, 8 May 2015 by Neil (Talk | contribs) (About the Glance Scene)

PreviousTable of ContentsNext
An Overview of WatchKit GlancesA WatchKit Context Menu Tutorial


<google>BUY_WATCHKIT</google>


The tutorial outlined in this chapter will add a glance scene to the TableDemoApp created in the chapter entitled A WatchKit Table Tutorial and will make use of the various glance capabilities outlined in the previous chapter, including the addition of a glance to an existing Xcode project and the passing of context data from the glance to the main interface controller of the WatchKit app.

About the Glance Scene

The TableDemoApp project consists of a table containing a list of workout exercises for a fitness app. When a table row is selected by the user the app navigates to a second scene containing more detailed information about the chosen exercise. In this chapter, a glance scene will be added to this project, the purpose of which is to allow the user to display a summary of the exercise last selected in the WatchKit app. Through the use of context data, tapping the display from within the glance scene will launch the WatchKit app and automatically navigate to the corresponding detail scene.

If you have already completed the TableDemoApp project as outlined in the A WatchKit Table Tutorial and A WatchKit Table Navigation Tutorial chapters of this book, open the project in Xcode now. Alternatively, the completed project may be downloaded along with the other sample projects at the following URL:

http://www.ebookfrenzy.com/web/watchkit/index.php

Adding the Glance to the Project

To add the glance scene to the WatchKit app storyboard, select the Interface.storyboard file so that it loads into the Interface Builder tool and drag and drop a Glance Interface Controller object from the Object Library panel onto the storyboard canvas (Figure 19-1):


[[Image:|Image:]]

Figure 19-1


Next, add an interface controller to accompany the glance scene by Ctrl-clicking on the TableDemoApp WatchKit Extension entry in the Project Navigator panel, selecting the New File… menu option and creating a new Cocoa Touch Class named GlanceController and subclassed from the WKInterfaceController class.

Return to the Interface.storyboard file and select the Glance Interface Controller scene so that it highlights in blue. Display the Identity Inspector panel and select the newly added interface controller class from the Class drop-down menu.

The final step is to add a build scheme for the glance scene by duplicating and modifying the existing WatchKit App scheme. Begin by selecting the WatchKit App scheme in the run target menu as shown in Figure 19-2:


[[Image:|Image:]]

Figure 19-2


Display the run target menu again, this time selecting the Edit Scheme… menu option. Within the scheme editing panel, click on the Duplicate Scheme button located in the lower left hand corner and, in the name field located in the upper left hand corner, replace the “Copy of” text with a “Glance – “ prefix.

With the new scheme created and appropriately named, select the Run option on the left hand panel and change the Watch Interface option menu in the main panel from Main to Glance as shown in Figure 19-3:


[[Image:|Image:]]

Figure 19-3


Close the panel to commit the changes, at which point the glance is now integrated into the TableDemoApp WatchKit app extension.


Designing the Glance Scene Layout

The glance scene will use the default template layout consisting of the two Group interface objects. With the Interface.storyboard file displayed within Interface Builder, drag a Label object into each of the group containers within the glance scene as shown in Figure 19-4:


[[Image:|Image:]]

Figure 19-4


Select the Label object in the upper group container, display the Attributes Inspector panel and change the Vertical property listed under Position to Center.

Select the Label object located in the lower group and change both the Horizontal and Vertical properties in the Position section of the panel to Center. With the Label object still selected, click on the ‘T’ icon in the Font property field, change the Font menu to System and change the Style menu to Bold. Before clicking on the Done button, increase the Size value to 35:


[[Image:|Image:]]

Figure 19-5


On completion of these steps, the layout of the glance scene should match that outlined in Figure 19-6:


[[Image:|Image:]]

Figure 19-6


Establishing Outlet Connections

The interface controller for the glance scene will need access to the two labels to change the text that is displayed to the user. Keeping the Interface.storyboard file loaded in the Interface Builder tool, display the Assistant Editor panel and make sure that it is displaying the content of the GlanceController.swift file. Ctrl-click on the upper label in the glance scene and drag the resulting line to a position immediately beneath the class declaration line in the Assistant Editor panel. Release the line and create an outlet connection named titleLabel. Repeat this step to connect the lower label to an outlet named mainLabel. At this point the beginning of the GlanceController.swift file should read as follows:

import WatchKit
import Foundation

class GlanceController: WKInterfaceController {

    @IBOutlet weak var titleLabel: WKInterfaceLabel!
    @IBOutlet weak var mainLabel: WKInterfaceLabel!

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)

        // Configure interface objects here.
    }
.
.
}

Adding Data to the Glance Interface Controller

Now that the user interface of the glance scene is designed and the Label objects are connected to outlets in the interface controller, some data needs to be added to represent the information to be presented when the glance is displayed by the user. The information contained within the glance will consist of the currently selected exercise and a reminder of the duration or number of repetitions to be performed.

Select the GlanceController.swift file and add two data arrays to the class so that it reads as follows:

import WatchKit
import Foundation

class GlanceController: WKInterfaceController {

    @IBOutlet weak var titleLabel: WKInterfaceLabel!
    @IBOutlet weak var mainLabel: WKInterfaceLabel!

    let titleData = ["Warm-up", "Cardio", "Weightlifting", "Core", "Bike", "Cooldown"]
    let durationData = ["20 mins", "30 mins", "3 x 10", "2 x 20", "20 mins", "20 mins"]

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)

        // Configure interface objects here.
    }
.
.
}

Creating an App Group

When the glance is invoked by the user it will need to know which row within the corresponding WatchKit app was last selected by the user. The WatchKit app interface controller, therefore, needs to store this information in a location where it can also be accessed by the glance interface controller. Since this is a small amount of data, the ideal location is within app group user defaults as described in the chapter entitled Sharing Data Between a WatchKit App and the Containing iOS App.

Select the TableDemoApp target located at the top of the Project Navigator panel and click on the Capabilities tab in the main panel. By default, the Capabilities panel displays the settings for the iOS app target. To access the capability settings for the WatchKit Extension, use the menu located in the top left-hand corner of the capabilities panel as indicated in Figure 19-7:


[[Image:|Image:]]

Figure 19-7


When clicked, this menu will present a list of targets contained within the current project, one of which will be the TableDemoApp WatchKit Extension. Select this option and scroll down the capabilities list until the App Groups section comes into view. Switch App Group support On and select a suitable Apple developer account with which to associate the group when prompted to do so.

Click on the + button within the App Group section of the capabilities panel and add a new app group based on the application name and your organization identifier, for example:

group.com.ebookfrenzy.TableDemoApp

Once the new app group has been added, enable the checkbox next to it to ensure that the extension becomes part of the group as shown in the figure below:


[[image:|image:]]

Figure 19-8


Storing and Retrieving the Currently Selected Table Row

When the user selects a row within the WatchKit app, the index of that row needs to be saved into the app group user defaults. The selection of a table row results in a call to the didSelectRowAtIndex method of the main WatchKit app interface controller which now needs to be updated to save the current index value. Within the Project Navigator panel, select the InterfaceController.swift file, locate the didSelectRowAtIndex method and modify it as follows (noting that the app group identifier will need to be changed to match the one you created):

override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) {
    pushControllerWithName("DetailInterfaceController", context: detailData[rowIndex-1])

    let sharedDefaults = NSUserDefaults(suiteName: 
		"<YOUR APP GROUP IDENTIFIER HERE>")
    sharedDefaults?.setInteger(rowIndex, forKey: "index")
}

Within the glance interface controller, this stored index value needs to be retrieved and used to display the correct information within the glance scene. Edit the GlanceController.swift file and modify the willActivate method to update the labels in the scene with the current information:

override func willActivate() {
    super.willActivate()
    let sharedDefaults = NSUserDefaults(suiteName: 
		"<YOUR APP GROUP IDENTIFIER HERE>")

    let index = sharedDefaults?.integerForKey("index")

    if let arrayIndex = index {
        titleLabel.setText(titleData[arrayIndex - 1])
        mainLabel.setText(durationData[arrayIndex - 1])
    }
}

Test that the changes to the project work by running the WatchKit app within the Simulator environment and selecting the Warm-up row from the table so that the detail page appears. Next, within the Xcode toolbar change the run target to the Glance – TableDemoApp WatchKit App option and click on the run button. The glance scene should appear and display information relating to the selected Warm-up exercise as illustrated in Figure 19-9:


[[Image:|Image:]]

Figure 19-9


Tapping the glance scene will launch the WatchKit app. Note, however, that the app starts at the table scene and does not automatically navigate to the detail scene for the Warm-up exercise. To address this some code needs to be added to the project to pass context data from the glance to the WatchKit app.

Passing Context Data to the WatchKit App

As outlined in An Overview of WatchKit Glances, a glance interface controller specifies the context data to be passed to the WatchKit app via a call to the updateUserActivity method. The ideal location in which to place this method call is within the willActivate method of the glance interface controller.

Edit the GlanceController.swift file and modify this method as follows:

override func willActivate() {
    super.willActivate()
    let sharedDefaults = NSUserDefaults(suiteName: 
		"<YOUR APP GROUP IDENTIFIER HERE>")

    let index = sharedDefaults?.integerForKey("index")

    if let arrayIndex = index {
        titleLabel.setText(titleData[arrayIndex - 1])
        mainLabel.setText(durationData[arrayIndex - 1])

        updateUserActivity("com.payloadmedia.TableDemoApp", 
		userInfo: ["controller" : arrayIndex], webpageURL: nil)
    }
}

The added code calls the updateUserActivity method, passing through a dictionary object consisting of a key (“controller”) and the current array index value.

When the WatchKit app is launched by a tap on the glance scene, the handleUserActivity method of the main interface controller will be called and passed the dictionary object specified when the updateUserActivity method was called. This method now needs to be implemented in the InterfaceController.swift file as follows:

override func handleUserActivity(userInfo: [NSObject : AnyObject]?) {

    let controllerIndex = userInfo!["controller"] as! Int

    pushControllerWithName("DetailInterfaceController", 
		context: detailData[controllerIndex-1])
}

This method extracts the value associated with the “controller” key within the userInfo dictionary and uses it to display the DetailInterfaceController with the appropriate detail content.

Run the WatchKit app once again on the Simulator, this time selecting a different row from the table. Run the glance and tap the screen to launch the WatchKit app. This time, the WatchKit app should launch and display the previously selected detail scene.

Having verified that the code works within the Simulator, install and run the app on a physical Apple Watch device. Once the table appears, select a row and then press the digital crown twice to exit the app and display the time. Perform an upward swiping motion on the screen to display the glances and navigate to the table demo glance scene where the title and time should match the row selected in the main WatchKit app. Tapping the glance scene should launch the WatchKit app and automatically navigate to the corresponding detail scene.

Summary

Glances provide a quick way for users to view key information contained within a WatchKit app. This chapter has added a glance scene to the TableDemoApp project, using app group user defaults and context data to pass data back and forth between the glance and the WatchKit app.


<google>BUY_WATCHKIT</google>



PreviousTable of ContentsNext
An Overview of WatchKit GlancesA WatchKit Context Menu Tutorial