I have a custom UIButton which is a cloud, transparent black and white .png file, with no down state, just one image. When tapping and holding the finger over it, it turns dark grey. I'm trying to change that dark grey to something a little less oppressive. The button is out in the open in a view, not in a tab bar, tool bar, or navigation controller.
I've already tried setting tintColor (which the documentation helpfully informs me is only suitable for 'some' types of buttons, which no indication as to which).
I've also tried changing everything I can find in Interface Builder relating to highlight colours, default states, etc. Nothing has made a difference at all.
I've even tried setting the button's own image for its UIControlStateHighlighted state, but even this causes the dark grey overlay to appear when I hold my finger over it.
How can I change that colour? I've looked at numerous other issues here on SO and have been unable to find a solution that works for me. Any help would be greatly appreciated!
EDIT: I Solved the problem using a category of UIImage which adds a method that uses CoreGraphics to apply a tint to a provided UIImage. I then set THAT image as the highlight, and all is well. Seems a lot of hoop-la to change a colour Apple should've let us change, but c'est la vie.
You said you set a custom image for the UIControlStateHighlighted state. This should disable the default behaviour.
If you still have problems you can disable this effect by setting the adjustsImageWhenHighlighted property to NO and use whatever custom effect you want.
If adjustsImageWhenHighlighted = NO is not working,
set Button-Type to Custom (IB or programmatically).
Default Button-Type: System, changes behavior of highlighted button.
Swift 3:
myButton.adjustsImageWhenHighlighted = false
I was having a similar issue with a custom UIButton when the button was highlighting in grey every time it was pressed. I solved that problem by subclassing UIButton and in the implementation I overrode a single method, (void)setHighlighted: method and kept it empty:
- (void)setHighlighted:(BOOL)highlighted
{
// Leave empty to prevent super from doing whatever
// that it is doing to show the grey highlight.
}
That stopped any type of highlighting as I was not doing anything in the method. It's a better approach if all that you're trying to do is remove any highlighting effect.
So in your code, create a subclass of UIButton, override the setHighlighted method, and then make your custom button a subclass of this custom class.
You can write a custom button that does it
class ActionButton: UIButton {
var originalBackgroundColor: UIColor!
override var backgroundColor: UIColor? {
didSet {
if originalBackgroundColor == nil {
originalBackgroundColor = backgroundColor
}
}
}
override var isHighlighted: Bool {
didSet {
guard let originalBackgroundColor = originalBackgroundColor else {
return
}
backgroundColor = isHighlighted ? originalBackgroundColor.darken() : originalBackgroundColor
}
}
Related
I recently developed app which is compatible with Dark mode.
And dark mode also works fine.
Btw when I change from dark->light, light->dark mode from device, all colors change as expected except border color.
Let's say border color is black when light mode and white when dark mode and system setting is dark mdoe.
When I change system setting to light mode and return to app, all border colors stay white which is supposed be black.
Has anyone ever faced this issue and could you please help me solve this problem?
This is serious problem when I want to implement real-time theme update in app.
Thanks.
Thanks to #KurtRevis, I finally managed to solve the problem.
You need to listen to traitCollectionDidChange. If you want to change borderColor when appearance changes, you need code something like this.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
if #available(iOS 13.0, *) {
if (traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection)) {
// ColorUtils.loadCGColorFromAsset returns cgcolor for color name
layer.borderColor = ColorUtils.loadCGColorFromAsset(colorName: "CellBorderColor")
}
}
}
Hope this helps others
Depending on your circumstance you could make use of UIColor(dynamicProvider:), especially if traitCollectionDidChange(_:) is not an option (e.g. in a UIButton extension). Whenever the dynamicProvider is called upon to deliver the title color, it gives us an opportunity to update our border color as well. The example below just updates the border color to match the title color, but any other color could be used.
extension UIButton {
func applyLoginStyle() {
let titleColorProvider = UIColor { [weak layer] traitCollection in
let titleColor = UIColor(named: "myColor")!.resolvedColor(with: traitCollection)
layer?.borderColor = titleColor.cgColor
return titleColor
}
setTitleColor(titleColorProvider, for: .normal)
}
}
I'm building an app with a theme switcher and I'd like to use Appearance to switch the textColor of UILabels that have the default color (black -> white).
I assumed this would be possible and created subclasses for non-default labels, so I simply have to target UILabels with either no subclass or that kept the default color.
When I change the appearance with the following :
UILabel.appearance().textColor = UIColor.white
Every single Label, including subclasses and system labels become white, UIAppearance overriding control-level customization. I feel like it makes sense for UIAppearance to be the default state and for any customization to be applied on top of it.
Would there be any way to use UIAppearance to solve this? Or do I have to manually edit every label I have to add a subclass and a custom property?
Thanks for your help!
The only way I found to overcome this problem is to make the textColor variable read only. But it works:
UILabel.appearance().textColor = UIColor.orange
And the custom class:
class MyLabel: UILabel {
override var textColor: UIColor! {
get { return UIColor.blue }
set {}
}
}
This question already has answers here:
Change button background color using swift language
(12 answers)
Closed 6 years ago.
I am trying to make a settings page where if you select the 'Red' theme, then the red button's background goes red and the 'Blue' theme button's background goes white and vice versa. My problem is that I do not know how to edit another UIButton outside of the actual UIButton code. I know to edit the background color of regular UIButton you would write:
sender.backgroundColor = .red
However I am not sure how to do this outside the UIButton's code.
I have tried this:
themeCRed(sender.backgroundColor = .white)
(ThemeCRed is the button's name)
But I get the error, "Cannot convert value of type '()' to expected argument type 'UIButton'"
How can I edit the attributes of the other UIButton outside of it's function block?
If you know the intended outcome and there's few variations then forget about the sender and just set the intended uicolor to the desired uicolor
I don't sure that i understand you correct, but may be just make
#IBOutlet var myButton: UIButton!
in your ViewController or something...
and
myButton.backgroundColor = .white
hm?
You just need to identify the event of theme change and need to change the background colour of the buttons like below
yourButton.backgroundColor = UIColor.red
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
I can change the tintColor for my App (everywhere) in a setting pane.
When I change the tintColor, and after that try to return to the default tint color, some buttons in NavBar don't return to blue, how can I handle this?
To verify:
- create a new project Master/Detail
- In the detail view: add Two buttons, named: "Red Interface" and "Blue interface"
- In DetailViewController, add the actions
#IBAction func tapRed(sender: AnyObject) {
view.window!.tintColor = UIColor.redColor()
}
#IBAction func tapBlue(sender: AnyObject) {
view.window!.tintColor = nil
}
Now run the application, create a timestamp, go to detail, tap redInterface, then blue interface
That's OK in the Detail View, but when you return to Master, the "+" button item is red, not blue.
I can fix the problem by setting a real blue color instead of nil, but that's not a long term solution, if Apple change the default tintColor.
Is this a bug? Is there something I can do to bypass this problem?
A quick workaround would be to fetch the default tint color once on the initial app load and store it somewhere (i.e. in the user defaults)
From Apple's iOS 7 UI Transition Guide (Specifically under the Using Tint Color section).
By default, a view’s tint color is nil, which means that the view uses its parent’s tint. It also means that when you ask a view for its tint color, it always returns a color value, even if you haven’t set one.
That's a good workaround!
In fact, I don't even need to store the color.
If I change to
#IBAction func tapBlue(sender: AnyObject) {
view.window!.tintColor = UIButton(type:UIButtonType.System).titleColorForState(.Normal)
}
That gives me the correct blue color, even if I changed the tintColor (probably because I don't address a button in the view hierarchy)