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.)

3

There are 3 best solutions below

4
On BEST ANSWER

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:).
1
On

I wrote this answer inspired by this stack Overflow answer

extension UIImage {
  
  func getImage(backgroundColor: UIColor)->UIImage?{
    
    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    backgroundColor.setFill()
    let rect = CGRect(origin: .zero, size: size)
    let path = UIBezierPath(arcCenter: CGPoint(x:rect.midX, y:rect.midY), radius: rect.midX, startAngle: 0, endAngle: 6.28319, clockwise: true)
    path.fill()
    draw(at: .zero)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
  }
  
}

With this extension, you can easily create UIImage instances with backgrounds of any color. Simply call the getImage(backgroundColor:) method on your UIImage instance and pass in the desired background color as a parameter.

Example

    let dataSource = ["Apple", "Mango", "Orange", "Banana", "Kiwi", "Watermelon"]
    let button = UIButton(primaryAction: nil)
    let actionClosure = { (action: UIAction) in
         print(action.title)
    }
    var menuChildren: [UIMenuElement] = []
    let config = UIImage.SymbolConfiguration(paletteColors: [.systemBackground])
    for fruit in dataSource {
      let action = UIAction(title: fruit, image: UIImage(systemName: "checkmark.applewatch", withConfiguration: config)?.getImage(backgroundColor: .brown), handler: actionClosure)
        menuChildren.append(action)
    }
    button.menu = UIMenu(options: .displayInline, children: menuChildren)
    button.showsMenuAsPrimaryAction = true
    button.changesSelectionAsPrimaryAction = true
    button.frame = .init(origin: view.center, size: .init(width: 100, height: 40))
    view.addSubview(button)

OutPut:

enter image description here

This will give you a new UIImage with the original image overlaid on a brown background. I hope is useful for change background colour of image.

6
On

I find the thread "set background color of [UIImage systemImageNamed: ]" instructive: the paletteColors property of UIImage.SymbolConfiguration allows you to define a palette of colors that the system will apply to the layers of a hierarchical symbol.

Meaning: for a symbol to support multiple colors using paletteColors, it must have hierarchical layer annotations (as mentioned in configurationWithHierarchicalColor:). Each color in the array corresponds to a layer in the symbol. If a symbol has only one layer or is not designed with hierarchical annotations, all colors except the first are ignored, and you end up with a monochrome image.

In the context of your question, if you want to set a background color for a system symbol, and there is no appropriate hierarchical symbol to use as a background, you would need to overlay the symbol onto a UIView with the background color set.

// Create a colored background view
let backgroundView = UIView()
backgroundView.backgroundColor = .yourDesiredBackgroundColor // Set your desired color

// Create the symbol configuration
let symbolConfiguration = UIImage.SymbolConfiguration(paletteColors: [.yourForegroundColor])
    .applying(UIImage.SymbolConfiguration(pointSize: 50, weight: .medium))

// Create the image with the symbol configuration
if let symbolImage = UIImage(systemName: "yourSystemSymbolName", withConfiguration: symbolConfiguration) {
    // Create an image view with the symbol image
    let imageView = UIImageView(image: symbolImage)

    // Add the image view as a subview to the background view
    backgroundView.addSubview(imageView)
    imageView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        imageView.centerXAnchor.constraint(equalTo: backgroundView.centerXAnchor),
        imageView.centerYAnchor.constraint(equalTo: backgroundView.centerYAnchor)
    ])
}

// Use `backgroundView` wherever you need the image with a colored background

Another approach: If the background shape you desire is available as a system symbol (such as a filled circle), you can layer this symbol behind your primary symbol. That creates an effect where the primary symbol appears to have a background.

// Configuration for the background symbol (e.g., a filled circle)
let backgroundSymbolConfig = UIImage.SymbolConfiguration(paletteColors: [.yourBackgroundColor])
let backgroundSymbol = UIImage(systemName: "circle.fill", withConfiguration: backgroundSymbolConfig)

// Configuration for the foreground symbol
let foregroundSymbolConfig = UIImage.SymbolConfiguration(paletteColors: [.yourForegroundColor])
    .applying(UIImage.SymbolConfiguration(pointSize: 50, weight: .medium))
let foregroundSymbol = UIImage(systemName: "yourPrimarySymbolName", withConfiguration: foregroundSymbolConfig)

// Combine symbols to create an image with a "background"
// Assuming you have a method to overlay these images appropriately

However, if there is a suitable hierarchical symbol that can be used to represent the background, you could set its color via the paletteColors property.
For instance:

// Create symbol configuration with palette colors for hierarchical symbol
let config = UIImage.SymbolConfiguration(paletteColors: [.backgroundColor, .foregroundColor])
let image = UIImage(systemName: "yourHierarchicalSymbolName", withConfiguration: config)
imageView.image = image?.withRenderingMode(.alwaysOriginal)

In this case, .backgroundColor would be applied to the background layer of the hierarchical symbol, and .foregroundColor to the foreground layer.


UIAction does not directly support background color customization. UIAction's styling follows the appearance of the context in which it is presented, such as a menu. For specific background coloring, you would need to customize the UI elements that contain the action (e.g., the menu).
See for instance "How to change text and background color UIMenu | UIAction (Swift 5)"