'Avoid UIImage fill color from bleeding into UIImageView

I want to fill a UIImage containing a transparent section, without the fill color bleeding outside the image, into the UIImageView (I.E. into the UIImageView space that exists because the image has a "Scale Aspect Fit" setting)

How can that be done?

I tried drawing masks/contexts, settings masksToBounds/clipsToBounds/isOpaque to true/false, but it bleeds (or the whole thing turns into one solid colored box).

What I want (notice how the inside is white, but around the image it's transparent and therefore main color. This screenshot is from the iOS 15 Settings app): screenshot with white fill

What I have as of now (image fill color bleeds outside image. This is my app): bleeding color hd

Notes:

  • I am using SF Symbols for the images
  • The images have a transparent section inside, which is what I want to fill with a color other than the main background color of the UIImageView (while I want the UIImageView background to be transparent)

SF Symbols used:

                     checkmark.square.fill
                     divide.square.fill"
                     arrow.up.and.down.square.fill
                     questionmark.square.fill
                     arrow.right.square.fill
                     arrow.left.square.fill


Solution 1:[1]

What I ended up doing is add a container view for each icon, put the icon in the container, give a cornerRadius to the container, constraints from icon to container, background color to icon, and white background color to the containers. Here is some info:

    // MARK: Properties

    let myDataSource = [Const.Title.check,
                        Const.Title.factorize,
                        Const.Title.list,
                        Const.Title.random,
                        Const.Title.next,
                        Const.Title.previous]
    let myImageSource = ["checkmark",
                         "divide",
                         "arrow.up.and.down",
                         "wand.and.stars",
                         "arrow.right",
                         "arrow.left"]
    let tintColorsArray: [UIColor] = [
        .systemGreen,
        .systemBlue,
        .systemPurple,
        .systemOrange,
        .systemTeal,
        .systemTeal
    ]


    // MARK: Table

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: menuCell) as! MainMenuTableViewCell
        cell.myLabel.text = myDataSource[(indexPath as NSIndexPath).row]
        let aConfig = UIImage.SymbolConfiguration(weight: .bold)
        let aImage = UIImage(systemName: myImageSource[(indexPath as NSIndexPath).row], withConfiguration: aConfig)
        cell.newImageView.image = aImage
        cell.newImageView.tintColor = .white
        cell.imageViewContainer.backgroundColor = tintColorsArray[(indexPath as NSIndexPath).row]
        cell.imageViewContainer.layer.cornerRadius = 6
        cell.accessoryType = .disclosureIndicator

        return cell
    }

interface builder screenshot

Solution 2:[2]

SF symbols recognize the transparent enclosed shape inside as a separate shape that can be filled with color.

What are looking for is rendering mode to fill the checkmark shape (for example). By default SF symbols use monochrome rendering mode, you can use Palette rendering or Multicolor rendering (this is supported in SF symbols 2.0 partially and in 3.0 fully)

4 rendering modes monochrome, hierarchical, palette and multicolor respectively.

Warning: some SF symbols are copyrighted and can not be used, also Apple warns against making SF symbols look like system icons.

You can check copyright, rendering modes & color symbols using SF symbols app, you can download it from here https://developer.apple.com/sf-symbols/

EDIT:

for your specific case, and because all symbols you want to use have a rounded corner rectangle you can add a white rounded corner rectangle image (that is slightly smaller than original symbol) behind your UIImage. Example

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2