Learning iOS

Rendering System Images in SwiftUI

Discover the symbolRenderingMode APIs to personalize your system images.

Balraj Verma
Mobile App Development Publication

--

SF Symbol Images

I came upon some good APIs when I was browsing through several for one of my tasks. I considered sharing it with you. Now let’s get going…🕺🏼

We’ve seen that changing the color of iOS icons is possible by instructing the system on how to render those images and applying tint to them. Additionally, Apple has added a few APIs specifically for system images, which we can use to alter the system images’ colors, opacity, and other properties. We’ll talk about rendering mode APIs for system images today.

I would advise you to check out the SF Symbol App for Mac before attempting to examine APIs impacts in your code. All of the parameters that we may use in code to observe the color effects in those images are enabled in the SF Symbol app. Even effects, animations, opacity, and virtually everything are visible right away; however, we will add some code in this tutorial.

SF Symbol images are created using layers. These layers can have their colors changed by using the renderingMode API. Additionally, Apple has named those symbols and images so that each dot represents a layer in reality and can receive color in accordance with that 🧐

For example, the cloud.sun.rain.fill symbol consists of three layers: the primary layer contains the cloud paths, the secondary layer contains the paths that define the sun and its rays, and the tertiary layer contains the raindrop paths. ~ Apple Documentation

layer representation in system images

We won’t observe those effects if we don’t define any modes for system images. The image will be a plane with all of the layers colored black. View the example image below

Without Rendering mode all layers are black
//We will use this example
struct ContentView: View {
var body: some View {
ZStack {
RadialGradient(gradient: Gradient(colors:[ .orange, .pink]), center: .top, startRadius: 50, endRadius: 900)
.ignoresSafeArea()
HStack(spacing: 10) {
Image(systemName: "cloud.rainbow.half.fill")
Image(systemName: "thermometer.sun.fill")
Image(systemName: "cloud.sun.rain.fill")
}
//1.
// .symbolRenderingMode(.multicolor)
//2.
// .foregroundStyle( Color.green,Color.black,Color.blue)

.font(.system(size: 60))
}
}
}

The symbolRenderingMode now offers the following option, which you can use:

  1. Select a rendering mode from the options below.

hierarchical: It does this by rendering symbols as several layers with varying foreground style opacities.

monochrome: A mode that uses the foreground style to represent symbols as a single layer.

multicolors: A mode that shows symbols as several layers, each with its own style or color.

palette: a mode that presents symbols as several layers, each with a different style applied to it.

With all the above options, we can change how the image appears. To observe the impacts, use the SF Symbol app on the sample below.

Only the foreground style of system images is being altered by this API. (In addition to using the built-in default system image, you may also utilize their method, which involves using the SF app to begin generating your own collections of images.)

See the effect on the below images if we add .symbolRenderingMode(.multicolor) to images. Also, it will override the other foregroundStyle provided along with symbolRenderingMode api with option multicolor.

Therefore, changing the color of an image in rendering mode is not always possible. However, by default, only a small number of images have layers configured with the ability to alter color and accept symbolRenderingMode api. You can check out all those in the SF symbols app. How would you go about changing the colors of other system images, though? Or what if you’d like not to use the symbolRenderingMode api’s default colors? 🤔

Yes, not all system images are made to apply colors using symbolRenderingMode option; however, we may still achieve this by using the foregroundStyle to apply color. Let’s attempt to alter the colors of the right side of the image, which is still black.

struct ContentView: View {
var body: some View {
ZStack {
RadialGradient(gradient: Gradient(colors:[ .orange, .pink]), center: .top, startRadius: 50, endRadius: 900)
.ignoresSafeArea()
HStack(spacing: 10) {
Image(systemName: "cloud.rainbow.half.fill")
Image(systemName: "thermometer.sun.fill")
Image(systemName: "cloud.sun.rain.fill")
Image(systemName: "humidity.fill")
}
// .symbolRenderingMode(.multicolor)
//2.
.foregroundStyle(Color.purple,Color.green,Color.yellow)
.font(.system(size: 60))
}
}
}

2. Actually, foregroundStyle accepts three parameters that can be applied to system images on their layers: primary, secondary, and tertiary, which will be the order of preference.

symbolrenderingmode generated by foregroundstyle API

Additionally, you can precisely observe the color sequence that we passed in the foregroundStyle api by comparing the cloud.sun.rain.fill image.

So, by assigning the primary, secondary, and tertiary color values to any system image in accordance with your app’s color scheme, we can accomplish the same result using the foregroundStyle API.

Images colors can also be altered by combining symbolRenderingMode and foregroundStyle together too, but you must first check the preview to see if the changes are producing the desired one. The multicolor option, however, will take precedence over the foregroundStyle colors(primary, secondary, tertiary).

And that’s it. Thank you for reading my post. I really appreciate your time. If you think it’s helpful, please clap or comment. And in the following one, I see you. 🙌

--

--