Search code examples
swiftuikituiimagesf-symbols

SF Symbols Hierarchical, Palette, and Multicolor rendering mode colors?


At WWDC 2021 Apple announced SF Symbols 3, which will support new multi-color SF Symbols in iOS 15 and macOS 12.

New color-rendering modes that add depth and emphasis to a symbol through layer annotation
https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/

What is the syntax for creating such an image in UIKit and Swift?

let configuration = UIImage.SymbolConfiguration(pointSize: 18, weight: .regular, scale: .large)
// set colors...?

let image = UIImage(systemName: "1.circle", withConfiguration: configuration)

How does one use the the new hierarchical, palette, and multicolor rendering modes in UIKit?

These new rendering modes and colors are visible in the SF Symbols 3 app:

SF Symbols Hierarchical Rendering Colors

SF Symbols Palette Rendering Colors


Solution

  • SwiftUI

    Hierarchical

    Use the .foregroundStyle modifier.

    From Apple:

    SwiftUI fills the first layer with the foreground style, and the others the secondary, and tertiary variants of the foreground style. You can specify these styles explicitly using the foregroundStyle(_:_:) and foregroundStyle(_:_:_:) modifiers. If you only specify a primary foreground style, SwiftUI automatically derives the others from that style.

    Image(systemName: "exclamationmark.triangle.fill")
       .symbolRenderingMode(.hierarchical)
       .foregroundStyle(Color.purple)
    

    Palette

    Use the .foregroundStyle modifier with 2 or 3 colors as parameters.

    From Apple:

    In this mode SwiftUI maps each successively defined layer in the image to the next of the primary, secondary, and tertiary variants of the foreground style. You can specify these styles explicitly using the foregroundStyle(_:_:) and foregroundStyle(_:_:_:) modifiers. If you only specify a primary foreground style, SwiftUI automatically derives the others from that style.

    Image(systemName: "exclamationmark.triangle.fill")
       .symbolRenderingMode(.palette)
       .foregroundStyle(Color.yellow, Color.cyan) 
    

    Multicolor

    Use the .foregroundColor modifier with 1 color, along with .renderingMode(original).

    From Apple:

    The multicolor behavior [is] achieved by using original template rendering mode, along with a blue foreground color. This mode causes the graphic to override the foreground color for distinctive parts of the image.

    Image(systemName: "person.crop.circle.badge.plus")
        .renderingMode(.original)
        .foregroundColor(.blue)
    

    UIKit

    Hierarchical

    Use the UIImage.SymbolConfiguration(hierarchicalColor:) initializer.

    From Apple:

    let config = UIImage.SymbolConfiguration(hierarchicalColor: [.systemTeal])
    imageView.image = image.applyingSymbolConfiguration(config)
    

    Palette

    Use the UIImage.SymbolConfiguration(paletteColors:) initializer and two or three palette colors.

    From Apple:

    let config = UIImage.SymbolConfiguration(paletteColors: [.systemTeal, .systemGray])
    imageView.image = image.applyingSymbolConfiguration(config)
    

    Multicolor

    Use the UIImage.SymbolConfiguration(hierarchicalColor:) initializer and preferringMulticolor().

    From Apple:

    Use this method (preferringMulticolor()) to acquire the multicolor variant of a symbol, if one exists. This method is the primary approach to retrieving multicolor symbols.

    For this color configuration to have an effect, your symbol image must have the following:

    • Its renderingMode set to UIImage.RenderingMode.alwaysTemplate or UIImage.RenderingMode.automatic.

    • Multicolor annotations. If your symbol doesn’t have multicolor annotations, the resulting image is a monochrome (template) symbol image. If you combine this configuration with a hierarchical or palette color configuration using applying(_:), the resulting symbol uses the multicolor variant, if one exists, and defaults to the hierarchical or palette variant otherwise.

    let config = UIImage.SymbolConfiguration(hierarchicalColor: [.systemTeal]).preferringMulticolor()
    imageView.image = image.applyingSymbolConfiguration(config)