Let’s talk about how to customize the appearance of symbol images in SwiftUI

Let’s talk about how to customize the appearance of symbol images in SwiftUI

Preface

Symbol images are vector icons from Apple’s SF Symbols library, designed for use on Apple platforms. These scalable images adapt to different sizes and weights, ensuring consistent, high-quality icons across our apps. Using symbol images in SwiftUI is simple, just use an Image view and the system name of the desired symbol. Here’s a quick example:

 import SwiftUI struct ContentView: View { var body: some View { Image(systemName: "star") } }

picture

size

Although the symbol is placed in an Image view, it should be treated as text. To adjust the size of the symbol, we can apply the font() modifier, just like in a Text view. This enables us to align the size of the symbol with different text styles, ensuring visual consistency in the UI.

 HStack { Image(systemName: "star") .font(.title) Image(systemName: "star") .font(.body) Image(systemName: "star") .font(.caption) }

picture

We can adjust the weight of a symbol using the fontWeight() modifier. This modifier changes the thickness of the symbol's stroke, allowing us to match or contrast the symbol with the surrounding text.

 HStack { Image(systemName: "star") .fontWeight(.light) Image(systemName: "star") .fontWeight(.bold) Image(systemName: "star") .fontWeight(.black) }

picture

To scale the image relatively to the font size, we should use the imageScale() modifier. There are three options: small, medium, large, which scale the symbol proportionally to the font size. If the font is not set explicitly, the symbol will inherit the font from the current environment.

 HStack { Image(systemName: "star") .imageScale(.small) Image(systemName: "star") .imageScale(.medium) Image(systemName: "star") .imageScale(.large) } .font(.headline)

picture

Resizing a symbol image by applying the resizable() modifier and setting the frame is not recommended, as doing so causes the image to stop functioning as a symbol image, affecting its layout and alignment with text.

color

The color of the symbol image can be easily customized using the foregroundStyle() view modifier in SwiftUI. This modifier allows us to directly set the color of the symbol image.

 Image(systemName: "star") .foregroundStyle(.orange)

picture

The foregroundStyle() modifier can take any ShapeStyle, including gradients, which opens up a wide range of customization possibilities for our symbol images. In this example, the star symbol uses a linear gradient from yellow to red, transitioning from top to bottom.

 Image(systemName: "star") .foregroundStyle( LinearGradient( colors: [.yellow, .red], startPoint: .top, endPoint: .bottom ) )

picture

Rendering Mode

We can further customize the appearance of the symbol image by using different rendering modes. SF Symbols has four different rendering modes that change the color and appearance of the symbol. Some rendering modes keep the entire icon the same color, while others allow for multiple colors.

To set the preferred rendering mode for symbol images in SwiftUI, we use the symbolRenderingMode() modifier.

monochrome

Monochrome is the default rendering mode. In this mode, each layer of the symbol is the same color.

 Image(systemName: "thermometer.snowflake") .symbolRenderingMode(.monochrome)

Layering

Layered mode renders the symbol as multiple layers with different opacity applied to each layer. The hierarchy and opacity are predefined in each symbol, but we can still customize the color using the foregroundStyle() modifier.

 HStack { Image(systemName: "thermometer.snowflake") Image(systemName: "thermometer.snowflake") .foregroundStyle(.indigo) } .symbolRenderingMode(.hierarchical)

The symbolRenderingMode() modifier can be applied directly to an image view, or it can be set in the environment by applying it to a parent view that contains multiple symbol images. This way, all symbol images within the parent element will be affected.

picture

Color Palette

Palette mode allows symbols to be presented in multiple layers, each with a different color. This mode is perfect for creating colorful, multi-layered icons.

 Image(systemName: "thermometer.snowflake") .symbolRenderingMode(.palette) .foregroundStyle(.blue, .teal, .gray)

We don't need to specify the palette rendering mode explicitly. If we apply multiple styles in the foregroundStyle() modifier, the palette mode will be activated automatically.

 Image(systemName: "thermometer.snowflake") .foregroundStyle(.blue, .teal, .gray)

picture

If we specify two colors for a symbol with three hierarchies defined, the second and third levels will use the same color.

 Image(systemName: "thermometer.snowflake") .foregroundStyle(.blue, .gray)

picture

Multicolor

Multicolor mode renders symbols using a fixed set of colors defined by Apple. When using multicolor rendering, we cannot customize the color of the symbol, it will use the predefined colors.

 HStack { Image(systemName: "thermometer.snowflake") Image(systemName: "thermometer.sun.fill") } .symbolRenderingMode(.multicolor)

picture

It’s worth noting that since these colors are fixed, they don’t adapt to light and dark patterns. For example, our thermometer symbol has a white outline and is invisible on a white background.

Not all symbols support every rendering mode. Symbols with fewer layers may look the same in different modes, and layered and palette modes look similar to monochrome.

Mutable Values

When displaying a symbol image in SwiftUI, we can provide an optional value between 0.0 and 1.0 that the rendered image can use to customize its appearance. If the symbol does not support mutable values, this parameter has no effect. We should check which symbols support mutable values ​​in the SF Symbols app.

 HStack { Image(systemName: "speaker.wave.3", variableValue: 0) Image(systemName: "speaker.wave.3", variableValue: 0.3) Image(systemName: "speaker.wave.3", variableValue: 0.6) Image(systemName: "speaker.wave.3", variableValue: 0.9) }

picture

A mutable value can represent a characteristic that changes over time, such as capacity or intensity. This allows the appearance of a symbol to change dynamically based on the state of the application.

 struct ContentView: View { @State private var value = 0.5 var body: some View { VStack { Image( systemName: "speaker.wave.3", variableValue: value ) Slider(value: $value, in: 0...1) .padding() } .padding() } }

In this example, the symbol speaker.wave.3 changes its appearance based on the value provided by the Slider.

picture

We should use mutable values ​​to communicate changes in state, such as volume, battery level, or signal strength, to provide users with a clear visual representation of the dynamic state. To convey depth and visual hierarchy, we should use a layered rendering mode that elevates certain layers and distinguishes between foreground and background elements within a symbol.

Design variants

Symbols can have different design variations, such as filled and slashed, to help communicate specific states and actions. Slashed variations can indicate that an item or action is unavailable, while filled variations can indicate a selection.

In SwiftUI, we can apply these variants using the symbolVariant() modifier.

 HStack { Image(systemName: "heart") Image(systemName: "heart") .symbolVariant(.slash) Image(systemName: "heart") .symbolVariant(.fill) }

Different symbol variations are used for various design purposes. Outline variations work well in toolbars, navigation bars, and lists, while filled variations are used to emphasize selected states.

 HStack { Image(systemName: "heart") .symbolVariant(.circle) Image(systemName: "heart") .symbolVariant(.square) Image(systemName: "heart") .symbolVariant(.rectangle) }

Different symbol variants serve different design purposes. Outline variants work well in toolbars, navigation bars, and lists, where symbols are often displayed alongside text. Enclosing a symbol in a shape such as a circle or square can enhance its readability, especially at smaller sizes. Filled variants give the symbol more visual emphasis due to its solid area, making them ideal for use in iOS tab bars, swipe actions, and accent color scenarios to indicate selection.

In many cases, the view that displays the symbol automatically selects the appropriate variant. For example, iOS tab bars typically use the filled variant, while navigation bars prefer the outline variant. This automatic selection ensures that the symbol can be used effectively in different contexts without having to specify it explicitly.

Sample Code

 import SwiftUI struct ContentView: View { @State private var value = 0.5 var body: some View { VStack { Image( systemName: "speaker.wave.3", variableValue: value ) .symbolRenderingMode(.hierarchical) .foregroundStyle(.blue) Slider(value: $value, in: 0...1) .padding() } .padding() } }

Run Demo

  1. Open Xcode and create a new SwiftUI project.
  2. Paste the above code into ContentView.swift file.
  3. Run the project to see the effect.

in conclusion

Enhancing symbol imagery in SwiftUI can significantly improve the look and feel of your app. By adjusting size, color, rendering mode, mutable values, and design variations, we can create icons that make our app more intuitive and visually appealing. SwiftUI makes these adjustments simple and easy, allowing us to easily implement and improve these customizations to provide a better user experience.

<<:  iOS 18 update push, you must know this new change!

>>:  Analysis of the core principles of high-performance lock-free queue Disruptor and its application in i-theme business

Recommend

How to play with short video information flow in 2019?

If you are a marketer and you haven’t heard of sh...

For KOL marketing, just do these 3 things!

In the social media environment, brand marketing ...

To you who are fighting the virus!

This article was first published in 2020 Recently...

How to segment users? 6 models and 5 dimensions

Nowadays, with the continuous development of the ...

2019 Zhihu product operation analysis!

“Q&A community + knowledge payment” How does ...

The Internet in 2016: Where has all the traffic gone?

The trouble with public accounts: disappearing re...

Is Android about to be taken away?

[[129047]] When Cyanogen CEO Kirt McMaster announ...

How do Xiaohongshu and Kuaishou create internet celebrity products?

There are thousands of companies in the world, bu...