swiftuikituiimagesf-symbolsuiaction

Is there a way to actually change the background color in UIImage.SymbolConfiguration of a system image? Or is it always clear?


You can easily change the various palette color(s) of a system image, for example, when used in an action in a menu:

let conf = UIImage.SymbolConfiguration(paletteColors: [blah])
    .applying(UIImage.SymbolConfiguration(pointSize: 50, weight: .medium))

let acn = UIAction(
    title: "Blah",
    image: UIImage(systemName: "whatever", withConfiguration: conf)
) { [weak self] _ in
    guard let self else { return }
    yourButtonProcess("bleh")
}

enter image description here

But is it actually possible to change the background color (of the image itself)?

The only way I know to fake it is to build a non-system image, eg https://stackoverflow.com/a/53500161/294884

Is it possible?

In short how to truly change the background color of a system image (for situations where you can't change the bg color of the thing holding it.)

Not wishing to stack up associated questions, but I'm also wondering if you can change the background color of a UIAction (i.e. for example to make "rainbow" color-coded menus).

Important ...

I think it's important to note that the absolutely key piece of information here is: it turns out SF Symbols in fact have a clear background and that's that. Very interesting. (Sure, obviously you could have one (or more I guess) palette element that happens to be a filling square, so it's "effectively" a background.)


Solution

  • The simple answer is "no, you can't change the background color using UIImage.SymbolConfiguration". An SF Symbol doesn't have a "background" in the general sense. The only exceptions are the small subset of symbols ending in .square.fill.

    There are various work arounds such as creating a new UIImage from the original, filling in the background color of the new image. You've posted a link to such a solution.

    There is a way to effectively change the answer to "yes", but it requires a bunch of work up front. If you have a limited number of SF Symbols that you wish to apply a background color to, you can use the SF Symbols app to create a set of custom symbols that are each a copy of the original symbol combined with a component, where the chosen component is the background that you want. A likely component for the background would be "square.fill".

    Once you create the set of custom symbols you can export each as an SVG. Create a new Asset in your project. For each SVG, add the symbol using "Symbol Image Set" and drag the SVG into the "Symbol SVG" square. Ensure that the "Render As" option is set to "Hierarchical" for each symbol. Ensure each symbol has a useful name (such as "map.square.fill" instead of "Symbol").

    Once your custom symbols are in place as assets, your code now becomes something like the following:

    let conf = UIImage.SymbolConfiguration(paletteColors: [.systemBackground, .systemRed])
        .applying(UIImage.SymbolConfiguration(pointSize: 50, weight: .medium))
    
    let acn = UIAction(
        title: "Blah",
        image: UIImage(named: "map.square.fill", in: nil, with: conf)
    ) { [weak self] _ in
        guard let self else { return }
        yourButtonProcess("bleh")
    }
    

    The first palette color is the main symbol color. The second palette color is the background color.


    Here are more complete steps for creating and installing a custom symbol with a background using SF Symbols 5.1 and Xcode 15.

    To create a single custom symbol with a background:

    1. Run the SF Symbols app on your Mac
    2. Find the symbol you wish to add a background to. For example, the map symbol.
    3. Right-click on the symbol and choose "Duplicate as Custom Symbol". This will add a copy of the symbol to the Custom Symbols section with a name such as custom.map.
    4. Right-click on the new custom symbol and choose "Combine Symbol with Component..."
    5. Choose the desired component. The most likely choice would be square.fill or one of the other .fill enclosures since the goal is to add the component as the new symbol's background.
    6. Click on "Create Symbols" and a new custom symbol will be added which will be a combination of the original symbol over the chosen background.
    7. Select the new symbol and click on the File menu then "Export Symbol...".
    8. Save the SVG file.

    To create a multiple custom symbols with a background:

    1. Run the SF Symbols app on your Mac
    2. Find a symbol you wish to add a background to. For example, the map symbol.
    3. Right-click on the symbol and choose "Duplicate as Custom Symbol". This will add a copy of the symbol to the Custom Symbols section with a name such as custom.map.
    4. Repeat steps 2 & 3 for every new symbol you need.
    5. Once all of the new symbols are created, select all of the symbols. Then right-click on one of the selected symbols and choose "Combine X Symbols with Component..."
    6. Choose the desired component. The most likely choice would be square.fill or one of the other .fill enclosures since the goal is to add the component as the new symbol's background.
    7. Click on "Create Symbols" and a new custom symbol will be added for each selected symbol. Each will be a combination of the original symbol over the chosen background.
    8. Select all of the new symbols with a background and click on the File menu then "Export Symbol...".
    9. Save the SVG files.

    Add SVG symbol files to Xcode project:

    1. With your project loaded in Xcode, select File -> New -> File...
    2. Select "Asset Catalog" under the Resources section. Click Next.
    3. Give the new asset catalog a name (defaults to Media) such as Symbols. Click Create.
    4. Select the new asset catalog in the project navigator, click on + and then Import... enter image description here
    5. In the file chooser, select all of the SVG files for your custom symbols and click Open.
    6. Ensure all of the newly added symbols are selected and change the "Render As" option to Hierarchical. enter image description here
    7. All of the images can now be used with the UIImage(named:) variants including UIImage(named:in:with:).