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:
