Animating SF Symbols on iOS 18

Published on: September 4, 2024

Over the years, Apple has been putting tons of work into the SF Symbols catalog. With SF Symbols, we’re able to leverage built-in iconography that will look familiar to users while also fitting into the Apple ecosystem very nicely. The fact that there’s thousands of symbols to choose from makes it a highly flexible and powerful catalog of icons that, in my opinion, should be every designer and developer’s first choice when they’re looking for visual components to add to their apps.

Initially, SF Symbols were pretty much static. We could configure them with a color and thickness but that was about it. Now that we’re a few years down the line, Apple has added multiple ways to animate SF Symbols.

In this post, I’d like to take a look at the current state of SF Symbol animations and explore some of the available animation options and styles that are available to us today.

If you prefer to learn through video instead of text, check out this video on my YouTube channel

Basic SF Symbol animations

Overall, the ways in which we can animate SF Symbols are plenty. It’s honestly quite likely that this post end up missing some fun technique that you’ve discovered and enjoy using.

The reason for this is that I’ve found that it’s not immediately obvious just how powerful SF Symbol animations can be.

At the very core, it’s really not that complex to animate an SF Symbol. For example, we could quite easily create the animation below with just a few lines of code:

Wiggle animation example

The code for creating an effect like that looks a bit like this:

Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
    .symbolEffect(.wiggle, options: .repeat(.continuous))

What’s fun is that some symbols lend themselves to certain animations better than other. A wiggle is usually a fine way to draw attention to a symbol.

Notice how in the animation above you can distinguish between three layers that exist. The AirPods case, the inner “radio waves”, and the outer “radio waves”. SF Symbols lets us apply animations that change individual layers one by one. For example, to indicate a “searching” or “charging” animation you could want to have both radio waves be empty, then fill the inner ones, then the outer ones, and then have them be empty again.

A bit like this:

Animated waves on Airpods case

We can achieve that by changing the symbol effect that we’ve applied:

Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
    .symbolEffect(.variableColor, options: .repeat(.continuous))

That’s pretty cool, right?

There’s a whole bunch of symbol effects available for you to try so I highly recommend to apply the symbolEffect view modifier to see which effects exist, and to see how they play with specific symbols. As you’ll see, some effects (like variableColor will work well with certain layered SF Symbols but not with others).

The variableColor effect is an effect that has a list of sub effects. In the example above, all layers get filled and then we reset back to a base state. This is equivalent to the following code:

Image(systemName: "airpodspro.chargingcase.wireless.radiowaves.left.and.right.fill")
    .symbolEffect(.variableColor.cumulative, options: .repeat(.continuous))

If you switch cumulative to iterative in the example above, the effect looks like this:

Iterative animation on Airpods case

I highly recommend that you take a look at the available options and play with them to see how much you can really do with SF Symbol animations.

In the code above I used options to set my animation up to be repeating. You can choose to repeat continuously like I did, or you can repeat a set number of times.

It’s also possible to set the repeat behavior to be periodic. That way, your SF Symbol can show its animation once every couple of seconds as a nice way to draw the user’s attention towards the symbol without being obnoxious:

A periodic wiggle effect on a bell

The code for this animation looks like this:

Image(systemName: "bell.circle")
    .symbolEffect(.wiggle, options: .repeat(.periodic(delay: 2)))

It’s pretty cool that we’re able to write animations this powerful with very little work. SF Symbols do a lot of the heavy lifting of building good looking animations for us.

It’s also possible to link a symbol effect to a specific value in your view so that the animation starts as soon as the linked value changes.

Here’s what the code to do that looks like:

Image(systemName: "bell.circle")
    .symbolEffect(.wiggle, options: .repeat(.periodic(2, delay: 2)), value: notificationsEnabled)

Button("Toggle Notifications") {
    notificationsEnabled.toggle()
}

Every time we click the button to change the value of notificationsEnabled we start our symbol effect which wiggles the bell twice before stopping our animation.

We can also link our effect to a boolean value that determines whether or not our effect is active at all:

Image(systemName: "bell.circle")
    .symbolEffect(.wiggle, options: .repeat(.periodic(delay: 2)), isActive: notificationsEnabled)

The code above is slightly different because it uses isActive instead of value to determine whether the animation is active. We’ve also gone back to a constantly repeating animation that will only be active whenever the notificationsEnabled property is true. As soon as it’s set to false, the animation will end.

It’s worth exploring which animations are available, and how you can mix and match different options and configurations in order to come up with some pretty cool animations.

Next, let’s take a look at symbol transitions.

SF Symbol Transitions

Sometimes, you might want to use an SF Symbol to represent a state-dependent piece of UI.

For example, you might present a notification bell to your user if they’ve enabled notifications but you might want to cross out the notification bell if the user turns off notifications.

The code to achieve that could look a bit like this:

Image(systemName: notificationsEnabled ? "bell" : "bell.slash")

Button("Toggle Notifications") {
    withAnimation {
        notificationsEnabled.toggle()
    }
}

When run, the result looks a bit as follows:

Jarring example of swapping symbols

It’s not great and luckily, we can do better. SF Symbols can now nicely animate between different variants of the same symbols in most cases.

For example, SF Symbols can animate our bell example like this if we apply the right configuration:

A nicely animated symbol transition

All that we need to do is provide a contentTransition for our symbol:

Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
    .contentTransition(.symbolEffect(.replace))

Pretty cool, right? The .replace transition will always try to perform the most appropriate transition to move from one symbol to the next. In this case, that’s by seamlessly adding or removing our slash.

If we combine this with a different rendering mode, the effect looks even better:

A symbol transition that animates colors and changes symbols

In the example above I’ve used a hierarchical rendering mode to automatically gain appropriate opacity levels for my symbol’s layers.

Image(systemName: notificationsEnabled ? "bell" : "bell.slash")
    .symbolRenderingMode(.hierarchical)
    .contentTransition(.symbolEffect(.replace))

Again, I encourage you to play around with different settings and options to see what you can come up with.

SF Symbols are a very powerful tool in your iOS development toolbox and I highly recommend that you spend some time exploring different options the next time you’re working on a design for your app’s UI. Adding the right animations at the right times can really make your app stand out in a good way.

Categories

SwiftUI

Subscribe to my newsletter