具有 resizableImageWithCapInsets 的 UIImage 在暗模式下不响应

UIImage with resizableImageWithCapInsets Does Not Respond in Dark Mode

有谁知道一种方法可以使使用 resizableImageWithCapInsets 拉伸的 UIImage 响应 light/dark 模式下的变化?我当前的实现仅在第一次绘制时考虑 dark/light 模式。

[thumbnailContainer addSubview:[self addTileBackgroundOfSize:thumbnailContainer.bounds]];

- (UIImageView *) addTileBackgroundOfSize:(CGRect)bounds {
    UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:bounds];
    UIEdgeInsets insets         = UIEdgeInsetsMake(10.0f, 49.0f, 49.0f, 10.0f);
    UIImage *backgroundImage    = [[UIImage imageNamed:@"UnivGalleryTile"] resizableImageWithCapInsets:insets];
    backgroundView.image        = backgroundImage;

    return backgroundView;
}

我想我可以在 traitCollection 委托方法中重新绘制它们,但我希望有更好的方法让它们响应。

似乎resizableImageWithCapsInsets 导致图像失去其动态、自适应特性。您也许可以尝试为两种外观创建图像,然后将它们再次组合成动态图像。查看 this gist 如何做到这一点。

我已经解决了,但是男孩这么丑。所以,如果有人有更好的解决方案,我愿意接受:

我首先将图像视图存储在 NSMutableArray 中:

- (UIImageView *) addTileBackgroundOfSize:(CGRect)bounds {
    UIImageView *backgroundView     = [[UIImageView alloc] initWithFrame:bounds];
        UIEdgeInsets insets         = UIEdgeInsetsMake(10.0f, 49.0f, 49.0f, 10.0f);
        UIImage *backgroundImage    = [[UIImage imageNamed:@"UnivGalleryTile"] resizableImageWithCapInsets:insets];
    backgroundView.image            = backgroundImage;

    // Store image for re-drawing upon dark/light mode change
    [thumbnailArray addObject:backgroundView];

    return backgroundView;
}

然后我在用户更改屏幕模式时手动重置背景图像:

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    for (int i = 0; thumbnailArray.count > i; i++) {
        UIEdgeInsets insets         = UIEdgeInsetsMake(10.0f, 49.0f, 49.0f, 10.0f);
        UIImage *backgroundImage    = [[UIImage imageNamed:@"UnivGalleryTile"] resizableImageWithCapInsets:insets];

        ((UIImageView *)[thumbnailArray objectAtIndex:i]).image = backgroundImage;
    }
}

首先,这里没有惊喜。当你说 resizableImage 时,你创建了一个新图像。它不再是您从资产目录中获得的图像,因此它失去了自动链接/动态性,当特征集合发生变化时,该图像会自动更改为另一个图像。

其次,这无关紧要,因为您可以创建 与任意两个图像(不在资产目录中)的链接。你通过 UIImageAsset class.

来做到这一点

这是一个有效的例子。假设 Faces 是资产目录中一对的名称,一个代表 Any,一个代表 Dark。我将提取该对中的每个成员,将 resizable 应用于每个成员,然后将 new 对连接在一起作为彼此的变体:

let tclight = UITraitCollection(userInterfaceStyle: .light)
let tcdark = UITraitCollection(userInterfaceStyle: .dark)
var smiley = UIImage(named: "Faces", in: nil, compatibleWith: tclight)!
var frowney = UIImage(named: "Faces", in: nil, compatibleWith: tcdark)!
let link = UIImageAsset()
let insets = UIEdgeInsets(top: 30, left: 30, bottom: 30, right: 30)
smiley = smiley.resizableImage(withCapInsets: insets)
frowney = frowney.resizableImage(withCapInsets: insets)
link.register(smiley, with: tclight)
link.register(frowney, with: tcdark)

或在Objective-C中:

UITraitCollection* tclight = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight];
UITraitCollection* tcdark = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
UIImage* smiley = [UIImage imageNamed:@"Faces" inBundle:nil compatibleWithTraitCollection:tclight];
UIImage* frowney = [UIImage imageNamed:@"Faces" inBundle:nil compatibleWithTraitCollection:tcdark];
UIImageAsset* link = [UIImageAsset new];
UIEdgeInsets insets = UIEdgeInsetsMake(30, 30, 30, 30);
smiley = [smiley resizableImageWithCapInsets:insets];
frowney = [frowney resizableImageWithCapInsets:insets];
[link registerImage:smiley withTraitCollection:tclight];
[link registerImage:frowney withTraitCollection:tcdark];

全部完成。请注意,在代码中不需要保留任何对象 (linksmileyfrowney)。 现在,如果您将一对中的一个成员插入图像视图,它会在用户 light/dark 模式更改时自动更改为另一个成员:

let tc = self.traitCollection
let im = link.image(with: tc)
self.imageView.image = im

我会在浅色和深色模式之间来回切换以证明这是有效的:

对于带有 .zero 插图的 .tiled 图像 - 存在一个删除配置的 UIKit 错误,因为它只检查 non-zero 插图,而没有考虑tiled 配置的零插入案例。

解决方法是:

let responsiveZeroEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0000001)
let darkImage = yourDarkImage.resizableImage(withCapInsets: responsiveZeroEdgeInsets, resizingMode: .tile)
let lightImage = yourLightImage.resizableImage(withCapInsets: responsiveZeroEdgeInsets, resizingMode: .tile)

然后将它们放入资产中。
诀窍是使用 0.0000001 插图。

我已向 Apple 提交错误报告:#9997202。