imageView.tintColor has no visible effect if the image uses its default rendering mode. Set the image rendering mode to .alwaysTemplate using image.withRenderingMode(.alwaysTemplate) or set ‘Render As’ to ‘Template Image’ in your Xcode Asset Catalog.Why this happens
Setting imageView.tintColor = .systemRed often fails to change the color of an image in UIKit or watchOS. The image continues to display in its original colors, or appears as solid black if the source asset is a monochrome shape.
This occurs because UIImage instances default to .automatic rendering mode (UIImage.RenderingMode.automatic). When an image with automatic rendering is placed into a standard UIImageView, UIKit resolves the mode to .alwaysOriginal. In original mode, UIKit draws the raw bitmap pixel data and completely ignores the enclosing view’s tintColor property.
To allow tintColor to recolor an asset, UIKit needs instructions to treat the image as a mask (an alpha-only template) rather than a full-color bitmap. In watchOS using legacy WatchKit (WKInterfaceImage), dynamic code-level rendering mode conversion is not exposed at runtime on the image view, making asset catalog configuration mandatory.
How to fix it
1. Set .alwaysTemplate in Swift code
The most common programmatic fix in UIKit is to generate a new UIImage reference configured with .alwaysTemplate using withRenderingMode(_:).
import UIKit
final class IconViewController: UIViewController {
private let iconImageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
// Load the image and create a template version
let originalImage = UIImage(named: "HeartIcon")
let templateImage = originalImage?.withRenderingMode(.alwaysTemplate)
// Assign to the image view and set the desired tint
iconImageView.image = templateImage
iconImageView.tintColor = .systemRed
view.addSubview(iconImageView)
iconImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
iconImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
iconImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
iconImageView.widthAnchor.constraint(equalToConstant: 44),
iconImageView.heightAnchor.constraint(equalToConstant: 44)
])
}
}
When alwaysTemplate is active, UIKit discards all color information in the asset and fills every non-transparent pixel with the view’s current tintColor. If the view is placed inside a hierarchy with a inherited tintColor (such as a custom UIView or UIWindow), setting the image to template mode will automatically inherit that tint.
2. Configure “Render As: Template Image” in Asset Catalogs
Changing the rendering mode directly in your Xcode asset catalog is the cleanest approach. It eliminates the need for boilerplate withRenderingMode(.alwaysTemplate) calls across your codebase.
- In Xcode, open your project’s
Assets.xcassetscatalog. - Select the image set that needs tinting.
- Open the Attributes Inspector in the right-hand utility panel (
Option + Command + 5). - Locate the Render As pop-up menu.
- Change the value from Default to Template Image.
Once configured, every instance of UIImage(named: "YourAsset") automatically loads with template rendering enabled. You can assign it directly to UIImageView.image and immediately alter tintColor without extra code.
3. Tint template images in watchOS (WatchKit)
In watchOS apps using WatchKit interface controllers, WKInterfaceImage does not support creating dynamic template copies via code. You must configure the rendering mode in the asset catalog first.
- Add the asset to the WatchKit App’s Asset Catalog.
- Set Render As to Template Image in the Attributes Inspector.
- Add a
WKInterfaceImageto your storyboard or interface controller. - Apply the tint programmatically using
setTintColor(_:):
import WatchKit
class StatusInterfaceController: WKInterfaceController {
@IBOutlet weak var statusImage: WKInterfaceImage!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// Set the image by name from the asset catalog
statusImage.setImageNamed("HeartIcon")
// Apply the dynamic tint color
statusImage.setTintColor(.red)
}
}
If you omit setTintColor(_:), watchOS applies the Global Tint specified in your WatchKit app target settings. If no Global Tint is set, watchOS defaults to light blue.
4. Recolor images in modern SwiftUI
If you are building your view in SwiftUI, the same principle applies. Bitmap images default to original rendering unless you chain the .renderingMode(_:) modifier before applying color.
import SwiftUI
struct TintedIconView: View {
var body: some View {
VStack(spacing: 16) {
// Custom asset requiring template mode
Image("HeartIcon")
.renderingMode(.template)
.foregroundStyle(.red)
// SF Symbols use template rendering by default
Image(systemName: "heart.fill")
.foregroundStyle(.blue)
}
}
}
SF Symbols created via Image(systemName:) are vector symbols configured as templates automatically. Custom PNG or SVG files added to asset catalogs must have either the .renderingMode(.template) modifier applied or the Asset Catalog “Render As” set to Template Image.
How to prevent it
- Mark monochrome icons, glyphs, and navigation shapes as Template Image in
Assets.xcassetsimmediately upon importing them. - Cache template images instead of calling
withRenderingMode(.alwaysTemplate)repeatedly inside fast-scrollingUICollectionViewCellorUITableViewCellreuse methods. - Prefer Apple’s built-in SF Symbols for standard iconography, as they automatically handle vector scaling, dynamic type, and template rendering without manual configuration.
- Test views in both Light and Dark modes to ensure the assigned
tintColorprovides sufficient contrast against the background.
FAQ
Why does tintColor work on SF Symbols without calling withRenderingMode?
SF Symbols are designed as vector glyphs rather than traditional raster bitmaps. UIKit and SwiftUI automatically configure them with template or hierarchical rendering modes by default, allowing them to adapt directly to the view hierarchy’s tint or foreground style.
Can I tint only part of a multi-color image using template mode?
No. Template mode treats all opaque and semi-opaque pixels identically, recoloring the entire shape using a single solid tint based on alpha values. To color individual layers independently, use multi-color SF Symbols, layered vector assets, or multi-palette SVGs configured in Xcode.
How do I revert an image back to its original bitmap colors?
Call image.withRenderingMode(.alwaysOriginal) on your UIImage instance, or set the Render As property in the Xcode Asset Catalog to Original Image. This forces UIKit to bypass any inherited or explicitly assigned tintColor.
Parts of this guide are adapted from content licensed under CC BY-SA 3.0; this article is shared under the same license.
