【发布时间】:2013-10-31 07:00:11
【问题描述】:
是否可以从情节提要或 xib 编辑器修改 UIImage 的 renderingMode?
目标是将tintColor 应用于特定的UIImageView 对象。
【问题讨论】:
标签: ios ios7 xcode-storyboard
是否可以从情节提要或 xib 编辑器修改 UIImage 的 renderingMode?
目标是将tintColor 应用于特定的UIImageView 对象。
【问题讨论】:
标签: ios ios7 xcode-storyboard
您可以不在.xib 文件中设置图像渲染模式,而是在.xcassets 库中设置。
将图像添加到资源库后,选择图像并打开 Xcode 右侧的属性检查器。找到属性“渲染为”并将其设置为“模板”。
设置图像的渲染模式后,您可以在.xib 或.storyboard 文件中为UIImageView 添加色调颜色以调整图像颜色。
这会在图像上的任何位置设置属性,而不仅仅是在一个界面构建器文件中,但在几乎所有情况下(我遇到过)这都是您想要的行为。
需要注意的几点:
UIImageView。我没有深入研究。UIKitComponents,例如UIButton 和UIBarButtonItem 中的图像。【讨论】:
UIImageView 上的色调颜色似乎存在错误,因此在运行应用程序时并不总是显示色调颜色。
您可以在 .xib 或故事板文件中执行以下操作:
(Obj-C)在UIImageView上创建一个类别:
@interface UIImageView (Utils)
- (void)setImageRenderingMode:(UIImageRenderingMode)renderMode;
@end
@implementation UIImageView (Utils)
- (void)setImageRenderingMode:(UIImageRenderingMode)renderMode
{
NSAssert(self.image, @"Image must be set before setting rendering mode");
self.image = [self.image imageWithRenderingMode:renderMode];
}
@end
(Swift 4) 为UIImageView 创建一个扩展:
extension UIImageView {
func setImageRenderingMode(_ renderMode: UIImage.RenderingMode) {
assert(image != nil, "Image must be set before setting rendering mode")
// AlwaysOriginal as an example
image = image?.withRenderingMode(.alwaysOriginal)
}
}
然后在xib文件的Identity Inspector中,添加一个runtime属性:
【讨论】:
在 iOS 7 和 iOS 8 上,在 Storyboard 或 xib 中使用带有 UIImageView 的模板渲染模式非常有问题。
UIImage 未从情节提要/xib 正确解码。如果您检查 viewDidLoad 方法中的 imageView.image.renderingMode 属性,您会注意到它始终是 UIImageRenderingModeAutomatic,即使您在 xcassets 文件中将其设置为 Render As Template Image。 p>
要解决此问题,您必须手动设置渲染模式:
self.imageView.image = [self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage 已正确解码,其renderingMode 属性反映了在 xcassets 文件中选择的内容,但图像未着色。
要解决此问题,您有两种选择:
tintColor 属性。或
UIColor *tintColor = self.imageView.tintColor;
self.imageView.tintColor = nil;
self.imageView.tintColor = tintColor;
您可以选择自己喜欢的选项,同时为图像正确着色。
(如果您使用 Xcode 6.2 编译,只需执行 self.imageView.tintColor = self.imageView.tintColor; 就足够了,但如果您使用 Xcode 6.3 编译,这将不再有效)
如果您需要同时支持 iOS 7 和 iOS 8,则需要两种解决方法。如果您只需要支持 iOS 8,则只需要一种解决方法。
【讨论】:
将 imageView RenderingMode 设置为使用情节提要中的 tint 颜色可以简化为单线:
[self.imageView setImage:[self.imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
然后图片和色调颜色都可以在Storyboard中设置。
【讨论】:
您可以通过扩展修复 .xib 问题:
import UIKit
// fixing Bug in XCode
// http://openradar.appspot.com/18448072
extension UIImageView {
override open func awakeFromNib() {
super.awakeFromNib()
self.tintColorDidChange()
}
}
来源:https://gist.github.com/buechner/3b97000a6570a2bfbc99c005cb010bac
太棒了,这个错误已经存在了 4-5 年了。
【讨论】:
您不能从storyboard 或xib 设置renderingMode。它可以通过编程方式访问。
例如:
UIImage *unSeletedImage = [UIImage imageNamed:@"UnSelected.png"];
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
【讨论】:
UIImage *selectedImage = [unSeletedImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
在 Storyboard 中设置 tintColor 和 Class。
//
// TintColoredImageView.swift
// TintColoredImageView
//
// Created by Dmitry Utmanov on 14/07/16.
// Copyright © 2016 Dmitry Utmanov. All rights reserved.
//
import UIKit
@IBDesignable class TintColoredImageView: UIImageView {
override var image: UIImage? {
didSet {
let _tintColor = self.tintColor
self.tintColor = nil
self.tintColor = _tintColor
}
}
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
override init(image: UIImage?) {
super.init(image: image)
initialize()
}
override init(image: UIImage?, highlightedImage: UIImage?) {
super.init(image: image, highlightedImage: highlightedImage)
initialize()
}
func initialize() {
let _tintColor = self.tintColor
self.tintColor = nil
self.tintColor = _tintColor
}
}
【讨论】:
很容易修复
只需创建类 UIImageViewPDF 并在情节提要中使用它
IB_DESIGNABLE
@interface UIImageViewPDF : UIImageView
@end
@implementation UIImageViewPDF
- (void) didMoveToSuperview
{
[super didMoveToSuperview];
self.image = [self.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
id color = self.tintColor;
self.tintColor = color;
}
@end
【讨论】:
另一种解决方案是创建一个UIImageView 子类:
final class TemplateImageView: UIImageView {
override func awakeFromNib() {
super.awakeFromNib()
guard let oldImage = image else { return }
image = nil
image = oldImage.withRenderingMode(.alwaysTemplate)
}
}
然后只需将 Interface Builder 中的类设置为 TemplateImageView。
【讨论】:
从情节提要中设置的简单方法:
@IBDesignable
public class CustomImageView: UIImageView {
@IBInspectable var alwaysTemplate: Bool = false {
didSet {
if alwaysTemplate {
self.image = self.image?.withRenderingMode(.alwaysTemplate)
} else {
self.image = self.image?.withRenderingMode(.alwaysOriginal)
}
}
}
}
在 iOS 10 和 Swift 3 上运行良好
【讨论】:
在 iOS 9 中,在 Interface Builder 中设置 tintColor 属性仍然存在问题。
注意,除了写行直接修改ImageView属性之外,一个可行的解决方案是在资产目录中设置渲染为:模板图像,并调用例如:
[[UIImageView appearanceWhenContainedInInstancesOfClasses:@[[MyView class]]] setTintColor:[UIColor whiteColor]];
【讨论】:
如果您创建一个 IBOutlet,您可以像这样在 awakeFromNib 方法中更改它...
self.myImageView.image = [self.myImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
虽然@Moby 的回答更正确 - 这可能更简洁。
【讨论】:
这个 bug 还在 iOS 12.1 中!对于storyboards/xibs:给UIImageView添加一个标签可以快速解决。
斯威夫特 4.2
view.viewWithTag(1)?.tintColorDidChange()
【讨论】:
extension UIImageView {
@IBInspectable var renderModeTemplate : Bool {
get{
return image?.renderingMode == .alwaysTemplate
}
set{
image = image?.withRenderingMode(newValue ? .alwaysTemplate:.alwaysOriginal)
}
}
}
在storyboard中选择UIImageView并选择inspector,设置属性renderModeTemplate = On
In Storyboard
【讨论】:
正如鲁道夫也提到above,我会定义一个简单的类,像这样:
import UIKit
@IBDesignable class TintImage: UIImageView{
override func layoutSubviews() {
super.layoutSubviews()
image = image?.withRenderingMode(.alwaysTemplate)
}
}
在此定义之后,只需将图像视图添加到情节提要并选择其自定义类为TintImage。这将激活情节提要中的“色调”选择。
【讨论】: