具有 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];
全部完成。请注意,在代码中不需要保留任何对象 (link
、smiley
、frowney
)。
现在,如果您将一对中的一个成员插入图像视图,它会在用户 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。
有谁知道一种方法可以使使用 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];
全部完成。请注意,在代码中不需要保留任何对象 (link
、smiley
、frowney
)。
现在,如果您将一对中的一个成员插入图像视图,它会在用户 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。