如何防止 UIButton 的图像颜色重置为默认值?

Dal*_*ale 4 uibutton uiimageview ibaction tintcolor swift

这个问题是关于 Swift 4,Xcode 9.3.1。

更改图像按钮颜色的过程已有详细记录。那不是问题。

这个问题是关于如果按钮恰好是内部目标,为什么图像按钮的颜色会重置为默认颜色IBAction,以及如何处理它。

我在 Xcode 中创建了一个新项目来演示我所看到的内容。这是一个在视图控制器中有一个 IBAction 的项目,它尝试更改按钮上图像的颜色。我向应用程序添加了三个按钮(oneButtontwoButtonthreeButton),并将它们连接起来,因此每个按钮都有以下插座:

为典型按钮定义的插座

每个按钮都定义了不同的图像。这是一个例子:

名为“local”的图像示例

这是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
  }
}
Run Code Online (Sandbox Code Playgroud)

oneButton单击每个图标会在输出窗口 ( 、twoButton、 )中显示相应的文本threeButton,具体取决于单击的图标。效果很好。

当应用程序启动时,第一张图像的颜色为黑色(默认),正如预期的那样。

单击twoButton会使第一个图像上的颜色变为蓝色,如预期的那样。

单击threeButton会使第一个图像上的颜色变为紫色,如预期的那样。

单击oneButton会使第一个图像上的颜色重置为默认值(黑色)。这不是预期的。

我想发生的事情是,因为按钮当前正在处理系统事件(触摸),所以我设置的颜色被某些系统进程擦除。

我更改了代码,以便调用Touch Up Inside,而不是,并且第一张图像的颜色确实变成了红色!但只有在触摸时...一旦我松开,颜色就恢复为默认值。myAction()Touch Down

我想要的是能够触摸oneButton并将其更改为代码中的任何颜色,并保持这种状态,而不是将其重置为默认颜色。

添加/编辑

上面的代码确实一遍又一遍地设置图像渲染模式。我意识到,没有要这样做。但是当我不这样做时,当应用程序在模拟器中运行时,颜色不会改变。只要不是被触摸的项目,上面的代码至少会改变图像的颜色。在下面的代码中,尽管 if/else 的相应部分myAction()运行,但.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
  }
}
Run Code Online (Sandbox Code Playgroud)

Dal*_*ale 5

设置模板图像

简而言之,您希望应用颜色的图像需要指定为模板图像。如果在图像资产的属性检查器中进行此指定,则原始问题中的所有代码都将起作用。任何呼叫都.withRenderingMode(.alwaysTemplate)将变得不必要。

在属性检查器中

除非将图像设置为模板图像,否则不会应用颜色。

当前的工作方式(Xcode 9.4、Swift 4.1)是在 GUI 属性检查器中将图像设置为模板图像。

在 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) 
}
Run Code Online (Sandbox Code Playgroud)