Streaming is available in most browsers,
and in the WWDC app.
Adopt Variable Color in SF Symbols
Explore how you can use Variable Color to make SF Symbols even more expressive. We'll show you how system-provided symbols use variable color and provide best practices and guidance for using it effectively. We'll also help you learn how to incorporate variable color into custom symbols using the SF Symbols app and its annotation tools.
- Have a question? Ask with tag wwdc2022-10158
- Search the forums for tag wwdc2022-10158
♪ Mellow instrumental hip-hop music ♪ ♪ Hi, there! I'm Paul, and I work on the SF Symbols app.
Today, we're going to talk about a brand-new feature of SF Symbols: Variable Color.
We'll be going over how to bring symbols with Variable Color into your projects, and how the SF Symbols app can help you with every step along the way.
First, we'll take a look at Variable Color in system-provided SF Symbols.
We'll go over how it works and when to use it.
Then, we'll go over how to bring Variable Color into your own custom symbols.
Before we get started, if this is your first time using SF Symbols, or if you just want a refresher, I recommend you watch last year's session, "Explore the SF Symbols 3 app," to find out more about how to find and organize symbols for your projects.
And if you haven't yet, check out Thalia's talk, "What's new in SF Symbols 4," for an overview of the visual design of SF Symbols and the different rendering modes we'll be showing today.
Now, let's talk about Variable Color.
Variable Color is a new feature of SF Symbols that allows you to affect the appearance of a symbol using a percentage value.
By changing this percentage value, you can easily create symbols that reflect values that can change over time, like signal strength or progress.
I think the best way to see how Variable Color works is to jump into the SF Symbols app and let the system speak for itself.
This year in the SF Symbols app, we added a new preview area here in the rendering inspector that allows you to see a symbol in every rendering mode at a glance.
You can also click on the different representations to switch between rendering modes.
There's also a new Automatic option here in the picker.
This option allows each symbol to choose its own preferred rendering mode, which you can see selected in the preview area here.
For example, this square.and.arrow.up symbol prefers Monochrome, while these iPhone symbols prefer Hierarchical.
Below the color controls, you'll find a new set of controls for Variable Color.
And there's a new category for symbols that support Variable Color, which is a great place to start experimenting.
Let's select this speaker symbol, switch to Multicolor, and switch to the gallery view to get a closer look.
I'll start by clicking this button to turn Variable Color on, and pull the slider all the way down to decrease the percentage we're using.
You can see pieces of the symbol dimming as the percentage value decreases.
And as I pull the slider back up, those pieces of the symbol regain all of their color.
If you keep an eye on the preview area, you can see this happening in all four rendering modes.
And if I switch back to grid view, you can see all of the symbols in the Variable category are reacting to the changes.
So what did we just learn about Variable Color? First off, Variable Color can be used with every single rendering mode available for SF Symbols.
Every system symbol that supports Variable Color supports it in Monochrome, Hierarchical, Palette, and Multicolor modes.
Second, there are no rules for how many parts of a symbol can be affected by Variable Color.
Some symbols only have one layer that's affected; some have dozens.
Regardless, because Variable Color is controlled using percentages, you don't need to worry about this.
Just pass in a percentage and you're good to go.
So how does the system interpret those percentages? How do we know when a particular layer is going to have Variable Color applied? Well, like the rest of SF Symbols, we designed Variable Color to make your apps feel right at home on Apple platforms.
And that means that we took inspiration from the behavior of system-level indicators that you might be familiar with.
Let's look at this microphone symbol as an example.
The four dots on the left side of the microphone are each in a separate layer that participates in Variable Color.
So, each dot will activate when the percentage value crosses a certain threshold.
Those thresholds are spaced out evenly between zero and 100 percent.
Zero percent is a special case where no layers will be active.
Any value greater than zero percent will activate the first dot.
At 26 percent and greater, the second dot will also be activated.
Fifty-one percent and greater will activate the third dot.
And 76 up through 100 percent will activate all four dots.
So, Variable Color symbols will only appear visually empty at exactly zero percent.
You can see this behavior in system-level indicators like Wi-Fi strength and battery level.
Variable Color symbols will start appearing visually full at a value less than 100 percent.
You can see this behavior in system-level indicators like brightness and volume.
Now, this next symbol has three layers that use Variable Color, which means that the thresholds between layers might fall at awkward values like 33.3333 and 66.6667 percent.
We didn't want rounding errors to make symbols appear in unexpected ways, and we didn't want you to have to worry about how many significant digits you typed into your code.
So, thresholds between layers are rounded to the nearest percentage point, and we don't activate the next layer until you're one full percentage point above that rounded value.
So, for the first threshold, 33.3 percent rounds down to 33 percent, so the second layer activates one percentage point higher at 34 percent.
The final threshold rounds from 66.7 percent up to 67 percent, so the last layer activates at one percentage point higher than that, at 68 percent.
Of course, system-provided symbols are only one half of the story.
With the SF Symbols app, you can make and annotate your own custom symbols, and even better, you can make your custom symbols just as flexible and just as powerful as symbols provided by the system.
What do I mean by flexible and powerful? Well, system-provided SF Symbols are available in nine different weights, and each one of those nine weights is available at three different scales.
Each one of those 27 variants is available in four rendering modes with and without Variable Color.
That's 216 possible configurations.
Luckily, that doesn't mean that you need to draw your custom symbols 216 times.
Last year, to streamline the process of drawing symbols, we introduced variable templates.
When using this kind of template, instead of drawing 27 different combinations of weights and scales, you only need to draw three, and the system can generate the other 24 for you automatically.
After you've drawn your custom symbol, you can adopt different rendering modes through a process we call "annotation." Last year, if you wanted your symbol to adopt the Hierarchical and Palette rendering modes, you broke your custom symbol into different layers and assigned each layer a hierarchy level.
If you wanted your symbol to adopt the multicolor rendering mode, you broke your custom symbol into different layers again and assigned a color to each layer.
This meant that, to support all the available rendering modes, you had to manage two separate layer structures.
This year, we're streamlining that workflow with unified annotation.
Unified annotation uses a single-layer structure for a symbol, and shares that structure across all rendering modes.
So, instead of having to break your symbol into layers multiple times, you only need to do it once.
You now also have control over how your symbol will look in Monochrome rendering mode, in addition to the previous control you had over Hierarchical, Palette, and Multicolor.
And of course, unified annotation allows you to add Variable Color to your symbols.
So let's work on annotating a custom symbol to get to know unified annotation.
Last year, I was working on an app so my family could play card games together, even when we couldn't be in the same room.
A few months after that, I discovered a new obsession: puzzle cubes! So this year, I want to make an app that's going to help me practice solving mine.
I've got a custom puzzle cube symbol that I've made here on my desktop.
I'll drag it into the app to make a new custom symbol.
I based this symbol off of the system-provided cube symbol, and notice how I've left some of the details of the puzzle cube out.
This helps the symbol come across clearly, even at small sizes and different weights.
Now, remember this preview area from before? It's especially handy when annotating custom symbols.
As I make changes to the annotation, I can see how my custom symbol looks in all the different rendering modes at a glance.
And when I switch rendering modes by clicking here or picking a different option in the picker, the annotation controls in the list change accordingly.
Monochrome looks pretty good, but let's add some depth in Hierarchical mode.
I'll switch to that mode and pull the top and the side of the cube into new layers.
You can see that these new layers automatically get switched to the less-prominent secondary and tertiary levels.
This gives my symbol a little bit more depth and visual interest.
And remember that the Hierarchical annotation that we create is also used to support Palette rendering mode.
So I've just gotten two new rendering modes for the price of one.
Now, let's switch over to Multicolor mode to give this symbol some color.
Notice that when I switch to Multicolor mode, I still see the same layers that I separated out in Hierarchical mode.
Remember, in unified annotation, changes made to the layer structure in one rendering mode will carry through to all the others.
Let's make the front face red, the top face blue, and the side face yellow.
All right, this looks pretty great.
But the most important part of learning to solve a puzzle cube is practice, practice, and more practice.
So, I would love to use my cube symbol as a timer, and have it fill up with color as I spend more time practicing.
The solution for that is Variable Color.
These separate pieces in the front face look like a great place to add some variable color for our timer.
Let's separate out each of these pieces into a different layer.
Notice the order that I'm arranging these in the layer list.
The layers that I want to fill in first go on the bottom, and the layers I want to fill in last go on top.
Then, we'll select all of these layers and click on this button, which will enable Variable Color on all of them.
And that's it! Let's move the Variable Color slider around to see what happens.
Remember to keep an eye on the preview area to see what's happening in all the different rendering modes.
You can see that, as we change the percentage used in Variable Color, the front face adjusts its color in every rendering mode.
That's the power of unified annotation.
Because edits in one rendering mode can carry through to other rendering modes.
In many cases, you only need to do work once or twice to get great results in all four rendering modes.
And in situations where things are a bit trickier, the SF Symbols app still has you covered.
Let's look at a more complicated symbol.
Here's my cube symbol again, but this time, it's set inside of a circle, like many of the .circle.fill symbols in the system library.
Now, I've already started annotating this symbol.
You can see here that I've separated the circle and the parts of the cube into different layers.
My symbol looks great in Multicolor and Hierarchical modes, but in Monochrome, there's not much contrast between the cube and the circle behind it.
When all the paths in the symbol were in one layer, the cube paths created holes in the circle path, which looked great in Monochrome.
But now that I've moved the circle onto its own layer, the cube paths no longer create holes.
Instead, they create a solid cube on top of a solid circle.
So we can't see it very well.
Luckily, there's a new feature of unified annotation that can help us here.
We can choose Erase to make a layer create a hole in the layers behind it.
That's looking much better.
Now, let's add Variable Color again.
This time, I'll just select all of the pieces of the front face and choose Split into New Layers from the contextual menu.
Then I'll use this button to turn on Variable Color again.
And I'm done! And by the way, the paths are split up using the order that they appear in your symbol template, so if you pay attention to the order of your symbol's paths as you're drawing, you can save some time later.
So that is unified annotation in a nutshell.
It's a fast and powerful way to annotate your custom symbols.
You create one layer structure that applies across all rendering modes.
You can now control the appearance of your symbol in Monochrome rendering mode.
You can add Variable Color to individual layers in your symbol.
The z-order of the layers determines the order that they will fill in as the passed-in percentage increases, and the thresholds used for each layer are spaced evenly between zero and 100 percent.
And because it's part of the layer structure, when a layer opts in to Variable Color, this setting is shared across all rendering modes.
And there are two new layer options in unified annotation that make it easier to work with the new shared layer structure.
Setting a layer to Erase will use that layer's shape to erase layers behind it.
This is really useful in situations like Monochrome and Hierarchical symbols that have badges with a plus, a minus, or some other shape inside of them.
And finally, setting a layer to Hidden will exclude it from a particular rendering mode.
If you're in a situation where a layer truly can't be used across all the rendering modes, you can use this option to only apply that layer to certain modes.
All of these new features are supported by a new template format, 4.0.
When you're exporting a symbol from the SF Symbols app to import into Xcode, make sure that you export a 4.0 template to control Monochrome rendering and use Variable Color.
If you already have custom symbols that you annotated last year, they will be automatically updated to use unified annotation.
Your Hierarchical and Multicolor annotations will be brought in with no extra work required from you.
And, if you need to support earlier platforms, the previous 3.0 and 2.0 formats are still available for use.
Before we wrap up, there's one more thing I want to do.
I've had a lot of fun learning about how to solve puzzle cubes, but the best part so far is that my daughter saw me solving them and wanted to learn too.
So naturally, I also want her to be able to use my app to help her practice.
Now, she's starting kindergarten this fall, so we're going to start her off a little slower.
But this is where symbols with Variable Color truly shine.
We could design our timer UI like this.
Text and numbers are descriptive and helpful, but they could be intimidating for someone like her who's still learning or is unable to read the text.
But seeing a puzzle cube that looks just like the one she's holding, and seeing it fill up with color as time passes, is friendly and intuitive.
I don't even need to change my timer code; all I need to do is change the name of the symbol I'm using and keep passing in the same percentage values I used for my bigger cube symbol, and SF Symbols takes care of the rest.
And that's the power of symbols.
They allow us to convey ideas in a way that transcends language and text.
They give us a way to make our apps more inclusive.
And Variable Color in both system-provided symbols and your custom symbols gives us even more expressive power for concepts like progress, signal strength, and time.
All of that from three drawings and one unified annotation.
That's pretty amazing.
And, I might add, it's way easier than solving a puzzle cube.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.