SwiftUI graphic complication views also support tinting but with a different syntax.
I’ve already set up a file in the starter project, so open up HappyComplication.swift
And replace the contents of the body with the full-color image:
Image("full")
Note: If the Canvas isn’t showing, press Alt-Command-Enter to bring it up.
Desaturation
By default, SwiftUI complications will be desaturated, like the non-SwiftUI versions.
Add ClockKit to the top of the file:
import ClockKit
Then replace the code in previews to show as a complication:
CLKComplicationTemplateGraphicExtraLargeCircularView(
HappyComplication()
)
.previewContext()
Looks great, but it’s not tinted.
The previewContext will take a faceColor parameter to support tinting.
The parameter isn’t a Color, though. It’s a CLKComplicationTemplate.PreviewFaceColor enum.
Which means with the magic of SwiftUI’s ForEach, we can check out all of the colors at the same time! Just make sure to pass the face color to the preview context to tint to that color.
ForEach(CLKComplicationTemplate.PreviewFaceColor.allColors) {
CLKComplicationTemplateGraphicExtraLargeCircularView(
HappyComplication()
)
.previewContext(faceColor: $0)
}
Once the Canvas has finally refreshed, you’ll see your complication first in full-color, and then tinted to the seven pre-defined preview colors.
Using the enum value like this is an excellent way to ensure your complication looks good across multiple colors.
Layered
To use layered tinting, change the image name from full to outlines.
Image("outlines")
Next, add another modifier to the Image like so:
.complicationForeground()
By adding that modifier, you let watchOS know that it should consider the image as the foreground layer of the tinting.
At this point, your preview will show all the outlines, except the first one, in white.
What about the rest of the face?
You have to create the background layer as well.
So, wrap the image in a ZStack, and, instead of using the background image, add a Circle above it. That’ll appear behind the outline.
ZStack {
Circle()
...
}
When the Canvas refreshes the preview, you’ll have a circle behind the drawing outline, with the proper background color, even though you didn’t specify a color explicitly.
As a quick test, replace the GraphicExtraLargeCircularView with GraphicRectangularFullView in the preview.
CLKComplicationTemplateGraphic🟩RectangularFullView(
Notice how the colors are reversed in the full rectangular face?
Remember that watchOS decides whether to tint the foreground or the background, depending on the family.
Undo that last change, we do want to keep using the Circular version.
Rendering modes
There will be times when you still want a bit more control, depending on whether the user tints the watch face.
SwiftUI has you covered with the complicationRenderingMode environment value.
@Environment(\.complicationRenderingMode) var renderingMode
watchOS will set that property to .fullColor if the watch face displayed is multicolor, or .tinted if the user has a tinted face.
Which means we can use a conditional view, here
If the rendering mode is fullColor, use the “Full” image.
ZStack {
🟩if renderingMode == .fullColor {
Image("full")
.complicationForeground()
}
// previous code
}
Otherwise, use the tinted Circle and “outlines” that we set up earlier.
if renderingMode == .fullColor {
...
} else {
Circle()
Image("outlines")
.complicationForeground()
}
Now, when you look at the Canvas, the first image is still the full-color version.
Note that we needed to mark the full color image with complicationForeground. Otherwise, we lose that distinction in the else clause as well.
But by checking the rendering mode, you now have greater control.
You may want completely different images, depending on whether the complication is full-color or not.
Maybe you’d like a gradient on that circle?
.fill(LinearGradient(
gradient: Gradient(
colors: [.pink.opacity(1), .teal.opacity(0.1)]
),
startPoint: .top,
endPoint: .bottom))
You filled the circle with a linear gradient, from top to bottom. That’s standard SwiftUI code. However, notice the specified colors.
The first is pink, and the second is teal. I chose colors so that you could see they’ll be completely ignored.
When using a tinted complication, remember that watchOS only uses the opacity.
Try adding the background image in between the circle and the outlines.
Image("background")
In this background image, I set up the cat’s fur pattern to be partially transparent in the teal areas. That’s why you can still see the cute pattern around the nose and mouth in the tinted complication.
Update the complication controller
So far, you’ve performed all of your previewing of the complication from Xcode’s Canvas.
But to let the user pick your updated complication you must import SwiftUI in ComplicationController.swift:
import SwiftUI
And then modify localizableSampleTemplate(for:) to use the SwiftUI version:
let template = CLKComplicationTemplateGraphicExtraLargeCircularView(
HappyComplication()
)
return .init(date: Date.now, complicationTemplate: template)
Now build and run.
You should see the smiling kitty cat with the gradient behind them.