Getting rid of imageView tint on UIButton in UITableViewCell - ios

I have several buttons in my app that utilize images that are pictures.
For the buttons set in Interface Builder, I set the image in attributes inspector. It displays without a tint, as I desire. I checked the method used to set the image in interface builder is UIButton setImage:forState:
Now, if I try to do set the image of the button in cellForRowAtIndexPath in a UITableViewController, there's a tint over the image.
// This puts a tint over the button
customCell.myButton.setImage(buttonImage, forState: .Normal)
As a workaround, I threw an UIImageView behind the button, but when I animate the button the imageView doesn't move, which I find annoying.
I've also tried this:
// This results in a blank image on the button
customCell.myButton.imageView?.contentMode = .ScaleAspectFit
customCell.myButton.imageView?.image = buttonImage
If anyone's got suggestions re: what I'm doing wrong, I welcome your input.

It turns out imageWithRenderingMode solves the problem.
Creates and returns a new image object with the specified rendering mode.
A new image object with the specified rendering mode.
I needed to use the AlwaysOriginal case:
Always draw the original image, without treating it as a template.
let buttonImage = UIImage(named: buttonImageName)?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)

Related

Image in Button for Xcode is showing only tint color on old version [duplicate]

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
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.

UIButton with title and image, system selected background doesn't include image

I've got a UIButton of type .system that I am creating programmatically with Swift 4. It has a title and an image, and I'm toggling isSelected on and off on touch. When I toggle it on, there is a lovely coloured background added around the title of the image, but it doesn't extend far enough to include the image. These pictures explain far better than I can:
Is there any way to get that background to extend further over so the icon is a part of it? I don't mind changing the colour of the icon manually, but everything I've tried (titleEdgeInsets, contentEdgeInsets) has just moved the title and background around without actually extending it.
I would prefer to keep the button a .system button rather than a .custom one, and I like that the frame of the button (and therefore the touch area) is larger than that coloured background because it makes it easier to touch, I imagine if I was setting a solid colour backgroundImage to emulate the effect I would have to decrease the touch area to match, which I don't want.
Any help would be most appreciated! Thanks in advance!
Edit: I've added an image with button.layer.borderWidth = 1 to show the actual frame of the button, and how it differs from the isSelected background which appears around the title. (The gray is because it's in a grouped tableView)
The short answer is a .system button really only expects either an image or a title, not both. (See this for a more comprehensive matrix highlighting your issue)
There isn't really anything special about the .system button for your case, though. Create a .custom button and round button.layer.cornerRadius to get the corner effect.
If you use SF symbols, you can make the image part of the titleLabel:
let attachment = NSTextAttachment()
attachment.image = UIImage(systemName: "checkmark.circle")
let imageString = NSMutableAttributedString(attachment: attachment)
let textString = NSAttributedString(string: "Please try again")
imageString.append(textString)
Then set imageString to UIButton.attributedTitle.
https://www.hackingwithswift.com/articles/237/complete-guide-to-sf-symbols
Haven't tested with custom images.

what is the secret of eliminating black string between UINavigationbar and another view by using following method?

i have UINavigationbar and view underneath it.
and when i am saying following instructions the string is disappeared
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().setBackgroundImage( UIImage(), for:
.default)
why?
Per the documentation it looks like once you set setBackgroundImage it overrides the shadowImage with your custom implementation. On the navigation bar check out shadowImage it says:
"/* Default is nil. When non-nil, a custom shadow image to show instead of the default shadow image. For a custom shadow to be shown, a custom background image must also be set with -setBackgroundImage:forBarMetrics: (if the default background image is used, the default shadow image will be used).
*/
#property(nullable, nonatomic,strong) UIImage *shadowImage NS_AVAILABLE_IOS(6_0) UI_APPEARANCE_SELECTOR;"
So you are overriding the default with a blank image which in turns removes the default shadow or string as you call it.
Could you please tell us where the string is placed?
It could be string is same color as background color.
We can debug whether string is actually present in UI hierarchy using debug inspector with show clipped content enabled (which helps us to know any clipped views are present). I've attached screenshot for your reference.
View inspector

An UIBarButtonItem is colored with tint color. Can I get this displayed as it is?

The image below is the original one I want to display:
And I also put the following statement.
leftBtn.image = UIImage(named: "logo")
However, the image is displayes like the following one. I set the tint color as that dark grey.
Referencing this website disable tint on custom uibarbuttonitem images, I put this statement but it didn't make any change.
leftBtn.image?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
Is there any other way to make the image shown as I want? Any advice would be appreciated!
You should try this
leftBtn.image = UIImage(named: "logo").imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
That statement doesn't do anything. It returns the image but doesn't use it anywhere. You need to call the setImage method on your leftBtn to actually set the image.

UIButton backgroundImage versus image

I have UIButtons that I was trying to set the images to aspectFit. However using Storyboards I ran into some difficulty I subclassed UIButton and programatically set the imageViews of the buttons to ScaleAspectFit
#import "UIButtonWithImageAspectFit.h"
#implementation UIButtonWithImageAspectFit
-(void)awakeFromNib{
[self.imageView setContentMode:UIViewContentModeScaleAspectFit];
}
#end
This worked well and the buttons images display nicely.
However, now I have a need to swap out the images of the button programatically so I tried:
[_firstLetterButton setImage:[UIImage imageNamed:#"2CeadLitir.png"]];
But this does not work so according to advise here I must use:
[_firstLetterButton setBackgroundImage:[UIImage imageNamed:#"2CeadLitir.png"] forState:UIControlStateNormal];
which adds the image as a backgroundImage to the button. Now I have to images in the button.
that is scaled nicely as an image property of the button,
and another that is not scaled nicely as a background image displayed behind.
So I returned to the subclass of UIButton UIButtonWithImageAspectFit
and tried to change it so that it sets the contentMode of the backgroundImage rather than the image
But it does not seem to have a backgroundImage property that I can access but according to the documentation it does have
currentBackgroundImage
Property
However I cannot use the same method setContentMode on that currentBackgroundImage
Any ideas how to get around this?
You need to consider this illustration from Apple web-site.
It's from Buttons tutorial. In particular this:
State
A button has four states to configure for appearance—default, highlighted, selected, and disabled.
And form
UIButton class reference
Discussion
In general, if a property is not specified for a state, the default is to use the UIControlStateNormal value. If the UIControlStateNormal value is not set, then the property defaults to a system value. Therefore, at a minimum, you should set the value for the normal state.
And here is information about different UIControlState:
All this links is must-read for beginner iOS Developer.
Actually the UIButton has a method
- (void)setImage:(UIImage *)image
forState:(UIControlState)state
so All I needed to do was set the state when setting the image on the UIButton instead of on the UIButton.imageView

Resources