Swift Changing UISlider images and tint doesn't work as expected - ios

I have a slider in my ViewController:
#IBOutlet weak var timeSlider: UISlider!
When using the code:
timeSlider.setMinimumTrackImage(#imageLiteral(resourceName: "track"), for: .normal)
timeSlider.setMaximumTrackImage(#imageLiteral(resourceName: "track"), for: .normal)
timeSlider.setThumbImage(#imageLiteral(resourceName: "thumb2"), for: .normal)
My slider looks like this:
It works great and behaves as one would expect it to behave
Now I want to make the part before thumb have different color and the part after to also have different color, so I created a function which creates new images as templates (templates being an array) from images I use for my view:
func setTemplates(){
templates.removeAll()
for i in 0 ..< 10{
templates.append(playImg[i].withRenderingMode(.alwaysTemplate))
}
}
templates[5] is the same image as "thumb2"
templates[6] = "track"
and then I wanted to assign template[6] (which the image "track" converted to template) and color it in the same fashion I do with other images in the view like buttons, or to color labels etc. like this:
timeSlider.setMinimumTrackImage(templates[6], for: .normal)
timeSlider.setMaximumTrackImage(templates[6], for: .normal)
timeSlider.setThumbImage(templates[5], for: .normal)
timeSlider.minimumTrackTintColor = colors.primaryColor
timeSlider.maximumTrackTintColor = colors.detailColor
timeSlider.thumbTintColor = colors.secondaryColor
Where colors is a struct holding four different colors. But as you can see it doesn't work properly
The image thumb is being set to default one, it doesn't even behave properly as I can't move the thumb to 0.0 position of the slider and after I move it or the colors change, the part after thumb gets blue color which is default for slider.
I tried different ways to fight this problem but this is the closest I got it to working properly. At this point I'm starting to think it's a bug but maybe I made some mistake in my code. As I said I have buttons, labels, which I color the same way I tried here
button.setImage(templates[7], forState: .normal)
button.tintColor = colors.primaryColor
and it works
What am I doing wrong?

From the documentation for UISlider thumbTintColor:
Setting this property resets the thumb images back to the slider’s default images; any custom images are released by the slider. Setting this property to nil resets the tint color to the default and removes any custom thumb images.
Same for the two track tints.
If you want custom images then just set the custom images without also setting the tints.
In other words, set either the custom images or set the tints. Do not set both.

Related

Is there any way to use "withRenderingMode(.alwaysTemplate)" with default image by not adding any tint colour of a button?

I want to use "withRenderingMode(.alwaysTemplate)" to set an image on a button, but don't want to change any tint colour. Just want to set the default image.
let button = UIButton(type: .custom)
let image = UIImage(named: "image_name")?.withRenderingMode(.alwaysTemplate)
button.setImage(image, for: .normal)
button.tintColor = UIColor.red
Here I didn't want to use red tint colour. But if though I didn't use any tint colour, I didn't get actual image. I just want to set actual image.
If the image is already colored the way you like, then you could leave off the
withRenderingMode(.alwaysTemplate)
From documentation, Apple states that UIImage.RenderingMode.alwaysTemplate will:
Always draw the image as a template image, ignoring its color information.
Also, to ensure you get your original color you could use:
withRenderingMode(.alwaysOriginal)
Back to the documentation:
Always draw the original image, without treating it as a template.

How to change titleTextAttributes of UIBarButtonItem after it's pressed?

I have a navigation bar with several UIBarButtons that I initially display with an alpha of 0.5, and would like to display with an alpha of 1 after pressed. I am storing these attributes in normalAttributes and highlightedAttributes.
I set up the buttons in the following manner:
colorButton = UIBarButtonItem(title: "Colors", style: .plain, target: self, action: #selector(showColors))
colorButton.setTitleTextAttributes(normalAttributes, for: .normal)
colorButton.setTitleTextAttributes(highlightedAttributes, for: .selected)
This leads to the button briefly switching to the highlightedAttributes, which is expected. However, within the button's action showColors I then perform the following:
textButton.setTitleTextAttributes(highlightedAttributes, for:[])
I have also tried using .normal instead of []. Neither method seems to have any sort of effect on the button. Any help with this would be really appreciated.
The easiest way to accomplish this I can think of is using a custom view. Meaning, create a separate UIButton and make a reference to it in your class (e.g., let yourButton = UIButton()). Initialize your bar button item with UIBarButtonItem(customView: yourButton) and then use it however you want to.
Just note that you'll need to add your action/target pair on yourButton, not on the bar button item. Then in your action handler, showColors in your case, you can change the appearance of yourButton.
You can either toggle alpha directly or if it's just text we're talking about, you could do:
yourButton.setTitleColor(yourColor, for: .normal)
and
yourButton.setTitleColor(yourColorHalfAlpha, for: .selected).
Then in your showColors, just call yourButton.isSelected = !yourButton.isSelected to toggle the appearance.
A UIButton contains a UILabel as the titleLabel property. Just set its attributes the usual way instead of setting them via the button’s pass-through functions.

UIImageView.appearance is overriding UISegmentedControl.appearance

I've been trying to use the appearance proxy API to apply some default colors to some controls, but I've run into a problem.
When I apply a tint color to UISegmentedControl using something like...
UISegmentedControl.appearance().tintColor = UIColor.red
It generates this...
All good, but when I add...
UIImageView.appearance().tintColor = UIColor.green
it changes to...
Just to be clear, I have BOTH this lines in my code
UISegmentedControl.appearance().tintColor = UIColor.red
UIImageView.appearance().tintColor = UIColor.green
It doesn't matter in what order I call them, the result is the same, the UIImageView properties override the UISegmentedControls
I've spent over half a day trying to find a solution to this problem but can't seem to find anything that works.
Running Xcode 8.2, iOS 10, Swift 3
What am I doing wrong and how can I fix?
I am not sure about this, but I guess, UISegmentedControl uses UIImageView to create segments, i.e. the segments we see inside segmented control are UIImageViews and not UIViews. UISegmentedControl even has methods to setImage for a particular segment.
If above is true, we can use appearanceWhenContainedIn API of UIAppearance to set image view tint colour like this:
UIImageView.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).tintColor = UIColor.red
UIImageView.appearance().tintColor = UIColor.green

Keep aspect ratio for UIbuttons background image

I've been looking for hours and all I find is old answers saying that it cannot be done.
I have a button where I'd like the background image to be as large as it can be, while keeping its aspect ratio. The background image keeps getting streched no matter what I do. I've tried.
var bluecircle = #imageLiteral(resourceName: "BLUE.png")
monBreak.contentMode = UIViewContentMode.scaleAspectFit
monBreak.setBackgroundImage(bluecircle, for: UIControlState.normal)
Do I really need to make an imageview and put an invisible button over it? That seems like welcoming A LOT of new things that could go wrong.
I tried
#IBOutlet weak var monBreak: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
var bluecircle = #imageLiteral(resourceName: "BLUE.png")
let theimagebehindmonBreak = UIImageView(image: bluecircle)
theimagebehindmonBreak.frame = CGRectFromString( "{{0,0},{40,40}}")
monBreak.contentMode = UIViewContentMode.scaleAspectFit
monBreak.addSubview(theimagebehindmonBreak)
theimagebehindmonBreak.image=bluecircle
theimagebehindmonBreak.contentMode = UIViewContentMode.scaleAspectFit
This gets the aspect ratio right, but since I want the layout to be dynamic setting its size to fixed values won't work, plus it's not centered.
At first I tired simply applying the constraints of the button like so
var dacontraints = NSLayoutConstraint(monBreak.constraints)
But at this point I get the error "Cannot invoke initializer for type 'NSLayoutConstraint' with an argument list of type '{[NSLayoutconstraints]}'
This is killing me
Sounds like a solution where subclassing fits.
Subclass UIButton, add an ImageView in the init, size it to the frame, and set the contentMode properly.
Old question but since I was looking for the same I think this is still valid.
I was trying to do the same (as everyone says) for backgroundImage it is impossible. However, if your button will consist of only an icon, then first you should be using the setImage method AND if you are using it you'll have access to the imageView property of the button. Since this is an UIImageView you can set the contentMode to whatever you like.

UISlider with custom UIImage set to UIImageRenderingModeAlwaysTemplate

I'm trying to customise the look of a UISlider by setting custom images for the thumb, minimumTrack and maximumTrack like so:
let sliderThumbImage = UIImage(named: "slider-thumb")
volumeSlider.setThumbImage(sliderThumbImage, forState: .Normal)
let minTrackImage = UIImage(named: "slider-min-track")
volumeSlider.setMinimumTrackImage(minTrackImage, forState: .Normal)
let maxTrackImage = UIImage(named: "slider-max-track")
volumeSlider.setMaximumTrackImage(maxTrackImage, forState: .Normal)
This works as expected.
However, I would like to set these images to be template images, by setting their rendering mode to UIImageRenderingModeAlwaysTemplate
The problem is that if I then set the tintColor like this:
volumeSlider.thumbTintColor = UIColor.greenColor()
then the custom image is removed and the default image is used again.
How can I customise the image, and the tintColor simultaneously?
Edit: Docs seem to support the problem I'm having:
Note that you can only adjust the tint of the default track and thumb
images, not custom images. Setting the tint of a part of the slider
that has custom images associated with it will remove those images.
Source: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/UIKitUICatalog/UISlider.html
If you set the tint color on the UISlider itself, it will change the tint of your custom thumb image.
volumeSlider.tintColor = .green
You do however need to create the thumb image with its rendering mode set to alwaysTemplate. This can be done thru the asset manager or in code.

Resources