如何保持 UIButton 的图像颜色不会重置为默认值?
Posted
技术标签:
【中文标题】如何保持 UIButton 的图像颜色不会重置为默认值?【英文标题】:How can I keep the image color of UIButton from resetting to default? 【发布时间】:2018-05-29 19:49:56 【问题描述】:这个问题是关于 Swift 4,Xcode 9.3.1。
更改图像按钮颜色的过程有据可查。这不是问题。
这个问题是关于如果按钮恰好是IBAction
内的目标,为什么图像按钮的颜色会重置为默认颜色,以及如何处理它。
我在 Xcode 中创建了一个新项目来演示我所看到的。这是一个在视图控制器中有一个 IBAction 的项目,它试图更改按钮上图像的颜色。我在应用程序中添加了三个按钮(oneButton
、twoButton
、threeButton
),并将它们连接起来,因此每个按钮都有以下插座:
每个按钮都定义了不同的图像。这是一个例子:
这是ViewController
:
import UIKit
class ViewController: UIViewController
@IBOutlet weak var oneButton: UIButton!
@IBOutlet weak var twoButton: UIButton!
@IBOutlet weak var threeButton: UIButton!
override func viewDidLoad()
super.viewDidLoad()
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
@IBAction func myAction(sender: UIButton)
let oneImageView = oneButton.imageView
if sender == oneButton
print("oneButton")
oneImageView?.setImageColor(color: UIColor.red)
else if sender == twoButton
print("twoButton")
oneImageView?.setImageColor(color: UIColor.blue)
else if sender == threeButton
print("threeButton")
oneImageView?.setImageColor(color: UIColor.purple)
extension UIImageView
func setImageColor(color: UIColor)
let templateImage = self.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
self.image = templateImage
self.tintColor = color
单击每个图标会在输出窗口中显示相应的文本(oneButton
、twoButton
、threeButton
),具体取决于单击的是哪个图标。效果很好。
应用启动时,第一张图片的颜色是黑色(默认),正如预期的那样。
单击twoButton
会使第一张图像上的颜色变为蓝色,正如预期的那样。
单击threeButton
会使第一张图像上的颜色变为紫色,正如预期的那样。
单击oneButton
会使第一张图像上的颜色重置为默认值(黑色)。这是不预期的。
我想正在发生的事情是,因为按钮当前正在处理系统事件(触摸),所以我设置的颜色被某些系统进程清除了。
我更改了代码,而不是Touch Up Inside
,而是调用myAction()
Touch Down
,并且第一个图像的颜色变为红色!但只是在触摸的时候……我一松开,颜色就恢复了默认。
我想要的是能够触摸 oneButton
并将其更改为代码中的任何颜色,并保持这种状态,而不是将其重置为默认颜色。
添加/编辑
上面的代码确实反复设置了图像渲染模式。我意识到,不应该有必要这样做。但是当我不这样做时,应用程序在模拟器中运行时不会更改颜色。只要不是被触摸的项目,上面的代码至少会改变图像的颜色。在下面的代码中,虽然myAction()
中的if/else 的相应部分运行,但设置.tintColor
完全没有效果,无论单击哪个项目。我尝试了experiment
真假,无济于事。
class ViewController: UIViewController
@IBOutlet weak var oneButton: UIButton!
@IBOutlet weak var twoButton: UIButton!
@IBOutlet weak var threeButton: UIButton!
var oneImageView: UIImageView!
var oneImage: UIImage!
override func viewDidLoad()
super.viewDidLoad()
oneImageView = oneButton.imageView
oneImage = oneImageView?.image
let experiment = true
if experiment
oneImageView?.image = UIImage(named: "image")?.withRenderingMode(.alwaysTemplate)
else
oneImage.withRenderingMode(.alwaysTemplate)
oneImageView.image = oneImage
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
@IBAction func myAction(sender: UIButton)
//let oneImageView = oneButton.imageView
let tintColor: UIColor =
print("switch doesn't work here for some reason")
if sender == oneButton
print("oneButton")
return .red
else if sender == twoButton
print("twoButton")
return .blue
else if sender == threeButton
print("threeButton")
return .purple
else
return .cyan
()
oneImageView?.tintColor = tintColor
【问题讨论】:
这可能不是您正在寻找的,但是...您是否尝试过 (1) 将按钮类型从 custom 更改为system 然后 (2) 设置 tintColor?这就是我设置图像颜色的方式。 我确实尝试过更改按钮类型。这并没有帮助,但解决问题的方法是 xcassets 并将Render As
更改为Template Image
(来自Default
)。出于某种原因,将代码中的渲染模式设置为 .alwaysTemplate
并没有提供所需的结果。
你不应该直接改变按钮图像。有一些特殊的方法。请注意,按钮的每个状态都有一个图像。
@Sulthan,实际应用中按钮的状态不仅取决于按钮的状态,还取决于其他事物的状态,因此需要手动管理颜色。
@Dale 我只是说你不应该手动更改imageView.image
,因为每次更改按钮状态时都会设置它(例如,突出显示、选择等时)。你应该改用setImage(UIImage?, for: UIControlState)
。
【参考方案1】:
设置模板图片
简短的回答是,您希望应用颜色的图像需要指定为模板图像。如果在图像资产的属性检查器中进行了此指定,则原始问题中的所有代码都将起作用。对.withRenderingMode(.alwaysTemplate)
的任何调用都将变得不必要。
在属性检查器中
除非图像设置为模板图像,否则不会应用颜色。
当前的工作方式(Xcode 9.4、Swift 4.1)是在 GUI 属性检查器中将图像设置为模板图像。
完成此操作后,原始问题和已编辑问题中的所有代码版本都应按预期工作。
在代码中
在代码中将图像设置为模板图像似乎应该工作,但是,至少对于模拟器上的 Xcode 9.4、Swift 4.1,它没有永久性;第一次用户触摸会重置它。
在下面的代码中,.withRenderingMode(.alwaysTemplate)
确实会导致图标成为模板,但是一旦用户第一次触摸图标,它就会再次成为默认渲染。 这是真的在模拟 iPhone 中(未在物理设备上测试)。
override func viewDidLoad()
super.viewDidLoad()
oneImageView = oneButton.imageView
// NOT PERMANENT
oneImageView?.image = UIImage(named: "image")?.withRenderingMode(.alwaysTemplate)
【讨论】:
【参考方案2】:您不需要一次又一次地设置图像,只需将图像设置一次作为模板并稍后更改色调颜色。此外,使用switch
而不是多个if
s 更简洁。
override func viewDidLoad()
super.viewDidLoad()
oneImageView?.image = UIImage(named: "image").withRenderingMode(.alwaysTemplate)
@IBAction func myAction(_ sender: UIButton)
let tintColor: UIColor =
switch sender
case oneButton: return .red
case twoButton: return .blue
case threeButton: return .purple
default: return .clear
()
oneImageView?.tintColor = tintColor
【讨论】:
问题中的代码并不是为了优雅。这是为了证明一个问题。我认为您的回答没有解决将颜色重置为默认值的问题。 问题是你不必要地扩展 UIImageView 和设置图像。这种访问和修改图像的方式会导致您描述的重置。 感谢您的想法。我试图实现它,但无法让它工作(我将代码添加到原始问题中)。我尝试了几种变体,但设置 tintColor 从来没有做任何事情(myAction
运行,返回了适当的 tintColor,但设置 tintColor 没有效果)。我可以看到这应该可以工作,但它就是行不通,至少在我发布的这个微小的示例应用程序中是这样。
我在一个示例应用程序中实现了代码,它运行良好。你确定oneImageView
在执行myAction
时不为零吗?另外,oneImageView
的图像是否呈现为模板?
您的实现是使用带有图像的UIButton
s,它有效吗?哇。我的“从头开始”应用程序具有所有默认值......点击次数很少......不确定我错过了哪个点击。当myAction
被执行时,oneImageView
肯定不是零。在按钮的属性检查器中,我找不到按钮中包含的图像的“渲染为”以将其设置为模板。这就是我在代码中这样做的原因。以上是关于如何保持 UIButton 的图像颜色不会重置为默认值?的主要内容,如果未能解决你的问题,请参考以下文章
iOS:如果背景图像与按钮颜色相同,则更改我的 UIButton 的颜色