如何从Core Graphics生成动态的明暗模式UIImage?

时间:2019-10-08 18:11:06

标签: ios uiimage uikit ios-darkmode uiuserinterfacestyle

iOS 13引入了UIImage实例,它们自动采用当前的UIUserInterfaceStyle(即亮模式或暗模式)。但是,似乎只有一些方法可以从命名或系统映像(imageNamed:inBundle:withConfiguration:systemImageNamed:withConfiguration:)中构造此类映像。

是否可以通过Core Graphics动态生成通用的明暗模式UIImage(例如,使用两个CGImage或使用UIGraphicsImageRenderer)?

我看不到任何API,但也许我错了。

4 个答案:

答案 0 :(得分:4)

前几天对此做了一些研究(也需要此功能,但到目前为止尚未实现):

  1. 在代码中创建一个UIImageAsset
  2. 使用register(_:with:)中的UIImageAsset(提供userInterfaceStyle .dark / .light)作为特征收集参数https://developer.apple.com/documentation/uikit/uiimageasset/1624974-register
  3. 注册两个UIImage。

答案 1 :(得分:2)

+ (UIImage*)dynamicImageWithNormalImage:(UIImage*)normalImage darkImage:(UIImage*)darkImage{
    if (normalImage == nil || darkImage == nil) {
        return normalImage ? : darkImage;
    }
    if (@available(iOS 13.0, *)) {
        UIImageAsset* imageAseset = [[UIImageAsset alloc]init];
    
        // 注册 lightImage
        UITraitCollection* lightImageTrateCollection = [UITraitCollection traitCollectionWithTraitsFromCollections:
        @[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight],
          [UITraitCollection traitCollectionWithDisplayScale:normalImage.scale]]];
        [imageAseset registerImage:normalImage withTraitCollection:lightImageTrateCollection];
    
        // 注册 darkImage
        UITraitCollection* darkImageTrateCollection = [UITraitCollection traitCollectionWithTraitsFromCollections:
        @[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark],
          [UITraitCollection traitCollectionWithDisplayScale:darkImage.scale]]];
        [imageAseset registerImage:darkImage withTraitCollection:darkImageTrateCollection];
    
        return [imageAseset imageWithTraitCollection:[UITraitCollection currentTraitCollection]];
    }
    else {
        return normalImage;
   }
}

也许就是您想要的。

答案 2 :(得分:2)

您无需创建新的UIImageAsset ,而是从现有UIImage的{​​{1}}属性中引用一个属性,并在其中添加一个黑色使用imageAsset方法的图片变体。

UIImageAsset.register(_:with:)

或使用此 // Prepare a UIImage for light mode. let lightImage: UIImage! // Prepare a UIImage for dark mode. let darkImage: UIImage! // Register your dark mode image to the light mode image's image asset. lightImage?.imageAsset?.register(darkImage, with: .init(userInterfaceStyle: .dark)) // Now your light mode image actually becomes a dynamic image. Use it. someImageView.image = lightImage someButton.setImage(lightImage, for: .normal) 扩展名

UIImage

答案 3 :(得分:1)

这是我在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: darkTC)
            return lightImage
        }
        else {
            return light()
        }
    }
}

此实现:

  • 将当前特征与样式相结合(以便包含displayScaleuserInterfaceLevel
  • 在正确的特征集内执行自动关闭(以确保正确生成以编程方式生成的图像)​​

示例1

假设我们已经加载了两个变体:

let lightImage = ...
let darkImage = ...
let result = UIImage.dynamicImage(withLight: lightImage, dark: darkImage)

示例2

假设我们想要一张红色的图像,可以动态显示明暗,只需调用:

let result = UIImage.dynamicImage(withLight: UIImage.generate(withColor: UIColor.red),
                                       dark: UIImage.generate(withColor: UIColor.red))

其中generate的功能如下:

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()
    }
}

结果: enter image description here