Swift4(Xcode9.3.1)中UIButton作为IBAction触发源时图片颜色重置问题
我完全懂你碰到的这个糟心问题——点击其他按钮时,第一个按钮的图片颜色能正常修改,但点击它自己的时候,颜色就会跳回默认黑色。结合你用的Swift 4、Xcode 9.3.1环境,这个问题的核心是UIButton在交互过程中会切换状态(正常、高亮、选中),系统会自动根据这些状态调整tint颜色,而你的代码逻辑刚好和系统的状态更新流程冲突了。
先拆解下问题根源:
- 你之前在IBAction里反复调用
withRenderingMode(.alwaysTemplate)重新生成图片,这会干扰按钮内部的状态管理,尤其是按钮处于高亮(触摸中)状态时,系统会优先使用状态对应的渲染逻辑。 - 直接修改按钮内部
imageView的tintColor,不如直接操作UIButton本身的tintColor属性——UIButton会自动把这个值同步给内部的imageView,还能更好地处理状态切换。
下面给你两种可行的解决方案,结合你的代码做了针对性修改:
方案一:提前设置图片为Template模式,直接操作按钮的tintColor
这是最简洁也符合Apple设计规范的方式:
- 在
viewDidLoad里一次性把目标按钮的图片设置为alwaysTemplate模式,避免每次点击重复生成图片干扰状态。 - 在IBAction里直接设置按钮的
tintColor,如果需要点击按钮时高亮状态不改变颜色,可以同步设置highlightedTintColor。
修改后的代码如下:
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() // 提前将oneButton的图片设置为Template模式,只需执行一次 if let originalImage = oneButton.imageView?.image { oneButton.setImage(originalImage.withRenderingMode(.alwaysTemplate), for: .normal) // 可选:让高亮状态的图片和正常状态保持一致,避免触摸时变色 oneButton.setImage(originalImage.withRenderingMode(.alwaysTemplate), for: .highlighted) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @IBAction func myAction(sender: UIButton) { var targetColor: UIColor = .black switch sender { case oneButton: print("oneButton") targetColor = .red case twoButton: print("twoButton") targetColor = .blue case threeButton: print("threeButton") targetColor = .purple default: break } // 直接设置按钮的tintColor,替代修改内部imageView的操作 oneButton.tintColor = targetColor // 可选:同步高亮状态的tintColor,彻底避免触摸时颜色重置 oneButton.highlightedTintColor = targetColor } }
方案二:通过按钮状态回调保持颜色(适合复杂状态场景)
如果你的按钮需要处理选中、禁用等更多状态,可以通过重写按钮的setHighlighted(_:)方法,或者监听touchDown/touchUpInside组合事件来确保颜色不被重置,但方案一已经能覆盖大部分常规场景。
为什么你的原始代码会出问题?
- 点击
oneButton时,按钮会进入highlighted状态,系统会自动使用默认的高亮tint颜色(未设置的话就是默认黑色),而你的代码在IBAction里设置imageView颜色的时机,刚好被系统的状态更新逻辑覆盖了。 - 反复调用
withRenderingMode(.alwaysTemplate)会导致图片实例被频繁替换,干扰按钮的状态图片缓存机制。
另外你补充的代码里,experiment分支无效的原因是:withRenderingMode(.alwaysTemplate)方法会返回一个新的UIImage实例,而不是修改原有的oneImage,所以oneImageView.image = oneImage本质还是用的非Template模式的原图,自然tintColor设置不会生效。
内容的提问来源于stack exchange,提问作者Dale
相关产品推荐
相关产品推荐

