如何将UIButton的图像颜色从重置设置为默认值?

时间:2018-05-29 19:49:56

标签: swift uibutton uiimageview ibaction tintcolor

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

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

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

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

outlets defined for the typical button

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

example of image named '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
  }
}

单击每个图标会在输出窗口(oneButtontwoButtonthreeButton)中显示相应的文本,具体取决于单击的文本。这很好。

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

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

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

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

我想现在发生的事情是,由于按钮当前正在处理系统事件(触摸),因此某些系统进程会消除颜色设置。

我更改了代码,而不是Touch Up InsidemyAction()被调用Touch Down,第一张图片DID的颜色变为红色!但只有在触摸时......一旦我发布,颜色就会恢复到默认状态。

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

ADDITION / EDIT

上面的代码确实反复设置了图像渲染模式。我意识到,不应该这样做是必要的。但是当我没有这样做时,当应用程序在模拟器中运行时,不会改变任何颜色。上面的代码至少会改变图像的颜色,只要它不是被触摸的项目。在下面的代码中,虽然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
  }
}

2 个答案:

答案 0 :(得分:1)

您无需反复设置图像,只需将图像设置为模板一次,稍后更改色调颜色即可。此外,使用switch代替多个if来更清晰。

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
}

答案 1 :(得分:0)

设置模板图像

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

在属性检查器

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

当前的工作方式(Xcode 9.4,Swift 4.1)是通过在GUI Attributes Inspector中将图像设置为模板图像。

set template image attribute in 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) 
}