Search code examples
iosswiftxcodeuibuttonuikit

How do I turn off the blue overlay on the image I'm using with my UIButton?


So, I'm a relatively new coder and understand this may be a real simple fix but I can't seem to find how anywhere, just that people know it happens. It is also possible I've misunderstood some other core idea and that is why I can't seem to fix.

I've set up a UIKit button in my storyboard, added both an IBAction and IBOutlet for this button in my script (class? whatever the individual .swift files are called within a project), set the IBO to inherit from UIButton, all in the ViewController class. In the viewDidLoad function I have

button.setImage(UIImage (named: "logo"), for: .normal)

and another line of coder pertaining to a UILabel (everything is fine there). Below the viewDidLoad function I have an array and then the IBA with a little bit of code that shuffles the array and spits out 0 indexed spot onto the screen.

I've been trying to fix this for a few days now and assuming I've understood everything I've read, I've learned that UIImages are immutable (can't be changed) so that tells me that I need to fix this when declaring it in viewDidLoad. I've also learned that it being blue is default in the current swift/xcode state, and that it is a render mode issue, just turning that off will fix the problem. I can't for the life of me connect the last few dots and figure out how to actually tell Xcode to simply use the image I've provided it.

I'm looking for a code solution of course, but the knowledge of why it will work and any corrections/clarifications to what I think I've learned will be even more appreciated so I can help myself more in the future.

Thank you in advance. -Cyre


Solution

  • Since you haven't specified, I'm assuming the button's "Type" is set to "System" in the storyboard (the default button type when you drag out a new UIButton in storyboards).

    By default, system buttons take any image set on it and apply a template rendering mode to it, which makes the image render all non-transparent pixels as a flat color (e.g. the tint color of the button in this case, which is by default the system blue color that you're seeing).

    UIImages by default have a renderingMode of automatic, which means the actual effective rendering mode the image takes on is determined by whatever is using the image (in this case, the UIButton).

    You can, however, instantiate a UIImage with a renderingMode of alwaysOriginal so that it never is treated as a template image. There are a couple of ways to do this.

    1. Programmatically

    You can create a new image object with a new rendering mode in code by taking the image you're already creating:

    UIImage(named: "logo")
    

    and calling withRenderingMode(_:) on it to return to you a new UIImage object that you then set on your button:

    let logoImage = UIImage(named: "logo")
    let logoImageAlwaysOriginal = logoImage?.withRenderingMode(.alwaysOriginal)
    button.setImage(logoImageAlwaysOriginal, for: .normal)
    

    2. Asset Catalog

    An easier way than going the programmatic route above is to just change the image's default rendering type in your asset catalog. Click on the image you want to change in your asset catalog ("logo" in this case), then go to the Attributes Inspector (keyboard shortcut: option+command+4), and change the "Render As" attribute to "Original Image". Now, whenever you use or get this image from the asset catalog (either in your storyboards or in code), the image will have the rendering mode of .alwaysOriginal.


    You can either do any of the above options and keep the system button type, OR you can just change your button's type to "Custom" in the storyboard, as custom buttons do not apply a template rendering mode to their images by default. However, you lose some nice things when not using the system button type, like the text color no longer is taken from the button's tint color, and the button doesn't have a nice fade animation when unpressed.