'Multiple complications in watchos

I'm building complications for a nutrition tracking app. I'd like to use offer multiple smaller complications, so the user can track their nutrition.

EG:

  • 'MyApp - Carbohydrates'
  • 'MyApp - Protein'
  • 'MyApp - Fat'

this way on the Modular watch face, they could track all three by using the three bottom 'modular small' complications.

I'm aware this can be achieved by only offering larger sizes that can display everything at once (eg the 'modular large' complication), but I'd like to offer the user choice about how they set up their watch face.

I can't see a way to offer multiple of the same complication, is there any way around this?



Solution 1:[1]

The previous answer is outdated. WatchOS 7 onwards, we can now add multiple complications to the same complication family for our app.

Step 1:

In our ComplicationController.swift file, we can make use of the getComplicationDescriptors function, which allows us to describe what complications we are making available in our app.

In the descriptors array, we can append one CLKComplicationDescriptor() for each kind of complication per family that we want to build.

func getComplicationDescriptors(
  handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
  var descriptors: [CLKComplicationDescriptor] = []
  for progressType in dataController.getProgressTypes() {
    var dataDict = Dictionary<AnyHashable, Any>()
    dataDict = ["id": progressType.id]
    
    // userInfo helps us know which type of complication was interacted with by the user
    let userActivity = NSUserActivity(
       activityType: "org.example.foo")
    userActivity.userInfo = dataDict

    descriptors.append(
       CLKComplicationDescriptor(
         identifier: "\(progressType.id)", 
         displayName: "\(progressType.title)",
         supportedFamilies: CLKComplicationFamily.allCases, // you can replace CLKComplicationFamily.allCases with an array of complication families you wish to support
         userActivity: userActivity)
    )
  }
  handler(descriptors)
}

The app will now have multiple complications (equal to the length of the dataController.getProgressTypes() array) for each complication family that you support.

But how do you now display different data and views for different complications?

Step 2:

In the getCurrentTimelineEntries and getTimelineEntries functions, we can then make use of the complication.identifier value to identify the data that was passed along when this complication entry was called for.

Example, in the getTimelineEntries function:

 func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
    // Call the handler with the timeline entries after the given date
    var entries: [CLKComplicationTimelineEntry] = []
    
    ...
    ...
    ...
    
    var next: ProgressDetails
    // Find the progressType to show using the complication identifier
    if let progressType = dataController.getProgressAt(date: current).first(where: {$0.id == complication.identifier}) {
      next = progressType
    } else {
      next = dataController.getProgressAt(date: current)[0] // Default to the first progressType
    }
     
    let template = makeTemplate(for: next, complication: complication)
    let entry = CLKComplicationTimelineEntry(
        date: current,
        complicationTemplate: template)
    entries.append(entry)

    ...
    ...
    ...

    handler(entries)
  }

You can similarly find the data that is passed in the getCurrentTimelineEntry and the getLocalizableSampleTemplate functions.

Step 3:

Enjoy!

Solution 2:[2]

There is currently no way to create multiple complications in the same family (e.g. Modular Small, Modular Large, Utilitarian Small etc.).

You could offer a way for the user to customize each complication to display Carbohydrates, Protein and Fat. You could even display different data for each complication family, but as far as having, for example, 2 modular small complications displaying different data, it is not possible yet.

You can see this if you put 2 of the same built in Apple complications in different places on your watchface they display the same thing. If Apple isn't even doing it with their own complications then it is more than likely impossible. Hope that explanation helps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ReactiveRaven
Solution 2 Zachary Bell