Here's my implementation in Swift 5
extension UIImage {
static func dynamicImage(withLight light: @autoclosure () -> UIImage,
dark: @autoclosure () -> UIImage) -> UIImage {
if #available(iOS 13.0, *) {
let lightTC = UITraitCollection(traitsFrom: [.current, .init(userInterfaceStyle: .light)])
let darkTC = UITraitCollection(traitsFrom: [.current, .init(userInterfaceStyle: .dark)])
var lightImage = UIImage()
var darkImage = UIImage()
lightTC.performAsCurrent {
lightImage = light()
}
darkTC.performAsCurrent {
darkImage = dark()
}
lightImage.imageAsset?.register(darkImage, with: UITraitCollection(userInterfaceStyle: .dark))
return lightImage
}
else {
return light()
}
}
}
This implementation:
- Combines the current traits with the style when evaluating each image (so as to include
displayScale
and userInterfaceLevel
)
- Executes the auto-closures within the correct trait collection (to ensure programmatically generated images are generated correctly)
- But registers the dark image without the current traits, only specifying the dark interface style (so, even if another trait property is modified like
userInterfaceLevel
or horizontalSizeClass
, usage of the dark image will be unaffected and still used if and only if the interface style is dark)
Example 1
Assume we have two variants already loaded:
let lightImage = ...
let darkImage = ...
let result = UIImage.dynamicImage(withLight: lightImage, dark: darkImage)
Example 2
Assume we want a red image, dynamic for light/dark, simply call:
let result = UIImage.dynamicImage(withLight: UIImage.generate(withColor: UIColor.red),
dark: UIImage.generate(withColor: UIColor.red))
where generate
function is as follows:
extension UIImage {
static func generate(withColor color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(color.cgColor)
context?.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image ?? UIImage()
}
}
The result:
