Creating Custom Apple Watch Complications, Part 1
Complications on watches have always been one of the key differentiators of expensive timepieces. Put simply, a complication is a function on a timepiece that does more than just tell the time—alarms, tachymeters, chronographs, calendars, and so on. Figure 1 shows an example of complications on a watch.
Figure 1 Gallet MultiChron Navigator (1943) with three complications: 45-minute recording chronograph, crown-controlled synchronizable second hand, and direction-finding 24-hour hand (Source: Wikipedia.)
Apple has aptly implemented complications on the various faces of its Apple Watch—complications that display data from applications such as Activity, Calendar, and so on. In watchOS 2, third-party apps can also display data in watch face complications. This article walks you through the process of creating an application that displays data on the Apple Watch complications.
Types of Complications
Complications on the Apple Watch are classified into the following families:
- Modular Small (see Figure 2)—a medium-sized square area used in digital interfaces
- Modular Large (see Figure 3)—a large rectangular area used in digital interfaces
- Circular Small (see Figure 4)—a small circular area used in analog interfaces
- Utilitarian Small (see Figure 5)—a small square or rectangular area used in analog interfaces
- Utilitarian Large (see Figure 6)—a small rectangular area that spans the width of the screen
Note that the first two families (Modular Small and Modular Large) are used in digital watch faces, and the rest are used in analog watch faces.
Figure 2 Modular Small complication.
Figure 3 Modular Large complication.
Figure 4 Circular Small complication.
Figure 5 Utilitarian Small complication.
Figure 6 Utilitarian Large complication.
The available complication types depend on the specific watch face. Some watch faces support multiple complication families; others don't support complications at all.
The ClockKit Framework manages the display of all complications data.
Creating the Project
Now that you have a better idea of the types of complications on the Apple Watch, let's create a project and see how a complication works. For this example, we'll create a project that displays the timing of the various movies played in a cinema.
- Using Xcode 7, create an iOS App with WatchKit App project (see Figure 7).
- Name the project Movies. Turn off the Include Notification Scene option and turn on the Include Complication option (see Figure 8).
Figure 7 Creating a WatchKit App project.
Figure 8 Check the Include Complication option to support complications in your application.
When the project is created, notice that a file named ComplicationController.swift appears under the Movies WatchKit Extension (see Figure 9).
Figure 9 The ComplicationController.swift file is used for displaying complication data.
The ComplicationController.swift file contains the definition for the ComplicationController class, which implements the CLKComplicationDataSource protocol. This protocol allows you to implement all the methods that pass your complication data to the ClockKit Framework. Specifically, you need to implement the following methods in the CLKComplicationDataSource protocol:
- getSupportedTimeTravelDirectionsForComplication:withHandler: is called to retrieve the time travel directions that your complication supports.
- getTimelineStartDateForComplication:withHandler: is called to retrieve the earliest date that your complication is ready to supply data.
- getTimelineEndDateForComplication:withHandler: is called to retrieve the latest date that your complication is ready to supply data.
- getPrivacyBehaviorForComplication:withHandler: returns the privacy behavior for the specified complication style.
- getCurrentTimelineEntryForComplication:withHandler: is called to display the timeline entry you want to display now.
- getTimelineEntriesForComplication:beforeDate:limit:withHandler: is called to retrieve past timeline entries for the complication.
- getTimelineEntriesForComplication:afterDate:limit:withHandler: is called to retrieve future timeline entries for the complication.
- getNextRequestedUpdateDateWithHandler: is called to get the next update time for the complication.
- getPlaceholderTemplateForComplication:withHandler: returns a static template to display in the selection screen for the complication.
The ClockKit Framework executes all the methods in the ComplicationController class in the background before the watch face displays your data in the complications. This execution model allows the user to see the data displayed in the complications instantly when the watch face lights up (such as when the user raises his wrist). This capability also gives the ComplicationController class sufficient time to fetch the data to be displayed in the complications.
In the Project Navigator, selecting the Movies WatchKit Extension target shows all the complication families supported by the app (see Figure 10). Remove the checks from any features you don't want your app to support.
Figure 10 Select which complication families your application will support.
Creating the Placeholder Template
Let's implement the first method in the ComplicationController class—getPlaceholderTemplateForComplication:withHandler:. This method returns a static template to display in the selection screen for your complication.
- Add the following statements in bold to the ComplicationController.swift file:
- In this method, you first check which type of complications you want to support by examining the CLKComplication object that is passed in. (For simplicity, this article supports both the Modular Small and Modular Large complications.) Once you've determined the type of complications you want to support, you need to use one of the many templates available for each complication:
- For the Modular Small complication, I'll use the CLKComplicationTemplateModularSmallRingText class. This class displays a single text string encircled by a configurable progress ring.
- For the Modular Large complication, I'll use the CLKComplicationTemplateModularLargeStandardBody class. This class displays a header row with two lines of text.
- To test the application, select the Complication—Movies WatchKit App scheme at the top of the Xcode window and then select iPhone 6 + Apple Watch—38mm (see Figure 11). This step deploys the iOS app and the WatchKit app to the iPhone 6 and Apple Watch Simulator, respectively.
- On the Apple Watch Simulator, press Command-Shift-2 to simulate a deep press. Then click on the watch face. Notice that you can now change the watch face, as shown in Figure 12.
- Press Command-Shift-1 to simulate a shallow press. Then swipe the watch face to the left. You should now see the Modular watch face, as shown in Figure 13.
- Click Customize. Notice that you can customize the watch face (see Figure 14).
- Click and swipe to the left. You'll see the watch face as shown in Figure 15.
- Select the complication named CALENDAR and move the scroll wheel on your mouse. The complication will change. Move the scroll wheel until you reach the MOVIES WATCHKIT APP item (the name of your app), as shown in Figure 16.
- Select the ACTIVITY complication in the middle of the bottom row (see Figure 17).
- Move the scroll wheel until you see MOVIES WATCHKIT APP (see Figure 18).
- Press Command-Shift-2 and then click on the watch face (see Figure 19).
- Press Command-Shift-1 and click on the watch face. The watch face should now look like Figure 20.
import ClockKit //---multipliers to convert to seconds--- let HOUR: NSTimeInterval = 60 * 60 let MINUTE: NSTimeInterval = 60 func getPlaceholderTemplateForComplication( complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) { // This method will be called once per supported complication, and // the results will be cached // handler(nil) var template: CLKComplicationTemplate? switch complication.family { case .ModularSmall: let modularSmallTemplate = CLKComplicationTemplateModularSmallRingText() modularSmallTemplate.textProvider = CLKSimpleTextProvider(text: "R") modularSmallTemplate.fillFraction = 0.75 modularSmallTemplate.ringStyle = CLKComplicationRingStyle.Closed template = modularSmallTemplate case .ModularLarge: let modularLargeTemplate = CLKComplicationTemplateModularLargeStandardBody() modularLargeTemplate.headerTextProvider = CLKTimeIntervalTextProvider(startDate: NSDate(), endDate: NSDate(timeIntervalSinceNow: 1.5 * HOUR)) modularLargeTemplate.body1TextProvider = CLKSimpleTextProvider(text: "Movie Name", shortText: "Movie") modularLargeTemplate.body2TextProvider = CLKSimpleTextProvider(text: "Running Time", shortText: "Time") template = modularLargeTemplate case .UtilitarianSmall: template = nil case .UtilitarianLarge: template = nil case .CircularSmall: template = nil } handler(template) }
In addition to the CLKSimpleTextProvider class, you use the CLKTimeIntervalTextProvider class to display a range of time. This class is smart enough to display the string efficiently, taking into consideration the space available for display and the user's region and locale.
Figure 11 Selecting the complication scheme in Xcode.
Figure 12 Changing the watch face.
Figure 13 Changing to the Modular watch face.
Figure 14 Customizing the watch face.
Figure 15 Changing to the next customizable screen of the watch face.
Figure 16 Changing the complication to your project.
Figure 17 Selecting the next complication to change.
Figure 18 Changing the complication for the project.
Figure 19 Deep press the watch face to exit the customization mode.
Figure 20 The watch face displays complication data from your app.
The first complication displays the following data:
- A header showing a time interval of 1.5 hours, starting from the time when the complication was added
- Two lines of text—Movie Name and Running Time
The second complication displays a three-quarter circle with the letter R inside it.
Setting Privacy Behavior
The next method you need to implement is the getPrivacyBehaviorForComplication:withHandler: method, which returns the privacy behavior for the specified complication style. If you want the complication data to display even when the watch is locked, use the ShowOnLockScreen enumeration:
func getPrivacyBehaviorForComplication( complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) { handler(.ShowOnLockScreen) }
Summary
In this article, you have seen what a complication is and how to implement it in your Apple Watch application. In the next article in this series, you will modify your application to display some real data and implement Time Travel—a feature in watchOS 2 that allows users to use the Digital Crown to scroll through time-sensitive complication data on the various watch faces.