I'm getting strange colors when assigning a custom UIColor to the background of UIPickerViews. I have created a color for textViews and pickerViews as follows:
let myTextViewBackgroundColor = UIColor(red: 192.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 0.35)
And I assign it as:
myTextView.backgroundColor = myTextViewBackgroundColor
keywordPicker.backgroundColor = myTextViewBackgroundColor
Here's what it looks like:
As you can see, the color of the textViews and the color of the picker are different. The difference seems more pronounced on a device than in this snapshot, but the custom color looks muddy, almost like it is mixed with a default gray background.
If I comment out the pickerView color item above, I get a gray color background:
If I choose a standard UIColor, it appears to work correctly. UIColor.yellowColor in this instance. If I choose white, that looks good, too.
I create the pickerView in code and assign it to a textField which has no background color assigned.
var keywordPicker : UIPickerView?
keywordPicker = UIPickerView()
keywordPicker?.delegate = self
keywordPicker?.dataSource = self
keywordsForItemTextField.inputView = keywordPicker
keywordPicker.backgroundColor = myTextViewBackgroundColor
And for what it's worth, I have a date picker that I created as a modal screen with it's own view controller. In that case, the picker is created on the storyboard. I still assign my background color with code and that picker shows the correct color.
tkanzakic's answer finally allowed me to change the background color of UIDatePicker.
Here's the Swift 4 version:
class CustomDatePicker: UIDatePicker {
var customBackgroundColor = UIColor.black
override func willMove(toWindow newWindow: UIWindow?) {
super.willMove(toWindow: newWindow)
if newWindow != nil {
inputView?.backgroundColor = customBackgroundColor
}
}
}
Change the customBackgroundColor property to your liking.
I'm pretty sure this is a result of the UIPickerView having that silvery-grey filter over it always (notice how it's grey when you have it set to white?)
This response does not expose the cause of the issue, but I've included my resolution in case it will help others. I created a label for the selected row display and set the background color of the label. This label color is true to the custom settings.
I give a nod to Making App Pie and article https://makeapppie.com/2014/10/21/swift-swift-formatting-a-uipickerview/
which was the inspiration. Set the background to white:
keywordPicker?.backgroundColor = UIColor.whiteColor()
Also I added a border so the picker looks like the textViews I created:
keywordPicker?.layer.borderColor = UIColor(colorLiteralRed: 212.0/255.0, green: 212.0/255.0, blue: 212.0/255.0, alpha: 1.0).CGColor
keywordPicker?.layer.borderWidth = 1.0
keywordPicker?.layer.cornerRadius = 7.0
keywordPicker?.layer.masksToBounds = true
Setup the label:
func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
let pickerLabel = UILabel()
var titleData : String = String()
if pickerView == keywordPicker {
titleData = crsuKeywordPickerList![row]
}
pickerLabel.text = titleData
pickerLabel.backgroundColor = myPickerBackgroundColor
pickerLabel.textAlignment = .Center
return pickerLabel
}//pickerView:viewForRow:...
The result:
As a second option as discussed above, if you instantiate the picker on the storyboard this problem does not appear.
In our case we have a wrapper around the UIPickerView to build a custom date picker. After setting the appearance proxy of the UITextField class to use dark mode for the inputView we have the same glitch if the first textField that becomes active is one with the custom picker as inputView, but if the user interact before with a textField with the normal keyboard as inputView the glitch do not appear.
In our particular case adding this hack to the wrapper view fix the issue:
- (void)willMoveToWindow:(UIWindow *)newWindow
{
[super willMoveToWindow:newWindow];
if (newWindow) {
self.pickerView.backgroundColor = self.colorPalette.inputViewBackgroundColor;
}
}
We also tried setting the color in the willMoveToSuperview: method but that does not work.
write your background color change code inside:-
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == self.tourtextfieldtextField {
//for background color of picker
datePickerView.backgroundColor = .red
//text color of picker
datePickerView.setValue( colorLiteral(red: 0, green: 0.5529411765, blue: 0.537254902, alpha: 1), forKeyPath: "textColor")
datePickerView.setValue(0.8, forKeyPath: "alpha")
}
}
swift 4.2 / xcode 10:
The background color need to be set in the main thread:
DispatchQueue.main.async {
keywordPicker.backgroundColor = myTextViewBackgroundColor
}
To remove the silvery-grey overlay on the UIPickerView you can add the following.
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
for subview in pickerView.subviews {
subview.backgroundColor = .clear
}
}
Related
I'm trying to change a UIView's backgroundColor based on its current color. E.g. say MyView is now red, on touch I want to make it blue and vice versa. But I noticed I cannot get the correct name of the UIColor to check the current color.
As an example, if I do:
if MyView.backgroundColor == .systemRed {
print("Red")
} else {
print("Not red")
}
This will always print "Not red", even if I explicitly set MyView.backgroundColor = .systemRed
When I check the color being used:
print("Color = \(MyView.backgroundColor)")
It prints: [...] name = systemRedColor
But when I change .systemRed to .systemRedColor, it gives the error
'systemRedColor' has been renamed to 'systemRed'
and I'm back at where I started.
Can anyone tell me what I am missing? How do I correctly read and set the backgroundColor of UIView?
.systemRed is one of the dynamic system colours that will be displayed differently depending on the view's current trait condition (i.e. Dark Mode / Light Mode). Therefore you need to access the current color using the .resolvedColor(with traitCollection:) function.
In Light Mode, systemRed will display as:
UIExtendedSRGBColorSpace 1 0.231373 0.188235 1
R255 G59 B48
In Dark Mode, systemRed will display as:
UIExtendedSRGBColorSpace 1 0.270588 0.227451 1
R255 G69 B58
if view.backgroundColor?.resolvedColor(with: view.traitCollection) == UIColor.systemRed.resolvedColor(with: view.traitCollection) {
print("true")
}
This will work with both dynamic and standard UIColor's.
You could also make an extension on UIColor to do this
extension UIColor {
class func compare(_ colorA: UIColor?, with colorB: UIColor?, in view: UIView) -> Bool {
colorA?.resolvedColor(with: view.traitCollection) == colorB?.resolvedColor(with: view.traitCollection)
}
}
Usage:
if UIColor.compare(self.view.backgroundColor, with: .systemRed, in: view) {
print("true")
}
You can try this.
self.bgView.backgroundColor = UIColor.red
print("self.bgView.backgroundColor")
if self.bgView.backgroundColor!.isEqual(UIColor.red){
print("Red")
} else {
print("No Red")
}
print(self.bgView.backgroundColor)
//it will print Red
I'm using UIAlertController for some actions.
But I'm not a big fan of the Blurry View Effect in the actions group view (see screenshot below).
I'm trying to remove this blurry effect. I made some research online, and I couldn't find any API in UIAlertController that allows to remove this blurry effect. Also, according to their apple doc here :
The UIAlertController class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.
I see that Instagram also removes this blurry view effect :
The only way I could find to remove it is to update the view hierarchy myself via an extension of UIAlertController.
extension UIAlertController {
#discardableResult private func findAndRemoveBlurEffect(currentView: UIView) -> Bool {
for childView in currentView.subviews {
if childView is UIVisualEffectView {
childView.removeFromSuperview()
return true
} else if String(describing: type(of: childView.self)) == "_UIInterfaceActionGroupHeaderScrollView" {
// One background view is broken, we need to make sure it's white.
if let brokenBackgroundView = childView.superview {
// Set broken brackground view to a darker white
brokenBackgroundView.backgroundColor = UIColor.colorRGB(red: 235, green: 235, blue: 235, alpha: 1)
}
}
findAndRemoveBlurEffect(currentView: childView)
}
return false
}
}
let actionSheetController = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet)
actionSheetController.view.tintColor = .lightBlue
actionSheetController.removeBlurryView()
This worked fine, it removed my blurry view effect:
What I'm wondering... Is my solution the only way to accomplish that? Or there is something that I'm missing about the Alert Controller appearance?
Maybe there is a cleaner way to accomplish exactly that result? Any other ideas?
It is easier to subclass UIAlertController.
The idea is to traverse through view hierarchy each time viewDidLayoutSubviews gets called, remove effect for UIVisualEffectView's and update their backgroundColor:
class AlertController: UIAlertController {
/// Buttons background color.
var buttonBackgroundColor: UIColor = .darkGray {
didSet {
// Invalidate current colors on change.
view.setNeedsLayout()
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Traverse view hierarchy.
view.allViews.forEach {
// If there was any non-clear background color, update to custom background.
if let color = $0.backgroundColor, color != .clear {
$0.backgroundColor = buttonBackgroundColor
}
// If view is UIVisualEffectView, remove it's effect and customise color.
if let visualEffectView = $0 as? UIVisualEffectView {
visualEffectView.effect = nil
visualEffectView.backgroundColor = buttonBackgroundColor
}
}
// Update background color of popoverPresentationController (for iPads).
popoverPresentationController?.backgroundColor = buttonBackgroundColor
}
}
extension UIView {
/// All child subviews in view hierarchy plus self.
fileprivate var allViews: [UIView] {
var views = [self]
subviews.forEach {
views.append(contentsOf: $0.allViews)
}
return views
}
}
Usage:
Create alert controller.
Set buttons background color:
alertController.buttonBackgroundColor = .darkGray
Customise and present controller.
Result:
Answer by Vadim works really well.
What I missed in it (testing on iOS 14.5) is lack of separators and invisible title and message values.
So I added setting correct textColor for labels and skipping separator visual effect views in order to get correct appearance. Also remember to override traitCollectionDidChange method if your app supports dark mode to update controls backgroundColor accordingly
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for subview in view.allViews {
if let label = subview as? UILabel, label.textColor == .white {
label.textColor = .secondaryLabel
}
if let color = subview.backgroundColor, color != .clear {
subview.backgroundColor = buttonBackgroundColor
}
if let visualEffectView = subview as? UIVisualEffectView,
String(describing: subview).contains("Separator") == false {
visualEffectView.effect = nil
visualEffectView.contentView.backgroundColor = buttonBackgroundColor
}
}
popoverPresentationController?.backgroundColor = buttonBackgroundColor
}
I have looked through other questions but can't find a definitive answer - I created my UIButton in my storyboard (not programmatically) and I am trying to tint the WHOLE button (not just text) on click. I have set my tint color to black and yet this does not affect the whole button.
I have tried setting my type to System as I heard that affects it but nothing has changed. Still no tint.
Furthermore I have to touch/click very "forcefully" (really press down if on device) to even trigger the tint color affecting the text on the button even though the button click registers.
The button's action func will be called so it does not affect functionality, but the text "highlighted state" seems to be only triggered if the user clicks really hard.
How can I tint the entire button? And why would the highlighted state only be triggered with really forced clicking?
Setting tint color -
Trying to implement with IBOutlet:
#IBOutlet var postBtn: UIButton!
postBtn = customButton()
postBtn.highlightedColor = UIColor.blueColor()
after creating custom class in new file:
public class customButton: UIButton {
public var highlightedColor = UIColor.blueColor()
public var unhighlightedColor = UIColor.clearColor()
override public var highlighted: Bool {
didSet {
if (highlighted) {
self.backgroundColor = UIColor.blueColor()
}
else {
self.backgroundColor = UIColor.clearColor()
}
}
}
}
I either get a bad access error if I declare postBtn initially as a customButton() or I am told postBtn has no member called highlightedColor. What am I doing wrong?
tint property sets the color of the button image and text.
As you don't have any image on your button, it only affect the color of the text
Also, tint will only affect the color of button's image when you set the button type to any except custom.
Now for example, we want to set the color of button image to red.
Then we will see:
In your case, you actually want to set the background color and title color of UIButton when button is highlighted.
For title color, you can directly use button.setTitleColor(UIColor.whiteColor(), forState: .Highlighted)
For background color, there is no direct method you can use, but you can create a custom UIButton which override the highlighted property of UIButton or use setBackgroundImage:forState:
Custom UIButton
public class customButton: UIButton {
public var highlightedColor = UIColor.blueColor()
public var unhighlightedColor = UIColor.clearColor()
override public var highlighted: Bool {
didSet {
if (highlighted) {
self.backgroundColor = UIColor.blueColor()
}
else {
self.backgroundColor = UIColor.clearColor()
}
}
}
}
Usage:
let button1 = customButton()
let button2 = customButton()
button1.highlightedColor = UIColor.redColor()
button2.highlightedColor = UIColor.blueColor()
button1.unhighlightedColor = UIColor.clearColor()
button2.unhighlightedColor = UIColor.blackColor()
setBackgroundImage:forState:
Another method to achieve what you want is use setBackgroundImage:forState:. You may need to create an UIImage from UIColor first.
Generate a image from UIColor:
func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
let rect = CGRectMake(0, 0, size.width, size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
Usage:
button1.setBackgroundImage(getImageWithColor(UIColor.redColor(), size: button1.bounds.size), forState: .Highlighted)
button2.setBackgroundImage(getImageWithColor(UIColor.blueColor(), size: button2.bounds.size), forState: .Highlighted)
Try like this,
1) Set UIButton type to custom from storyboard
then write like below,
Create IBoutlet for that button like,
#IBOutlet var btnSubmit : UIButton!
Create click event of that button,
#IBAction func btnSubmitClick(sender : UIButton)
{
if(sender.selected == false)
{
self.btnSubmit.backgroundColor = UIColor.redColor()
self.btnSubmit.selected = true
}
else
{
self.btnSubmit.backgroundColor = UIColor.blueColor()
self.btnSubmit.selected = false
}
}
This will change your whole button background color. Hope this will help you :)
With regards your first question, you would need to do this in code. The tint only affects the text. If you wanted the background colour to change, you would need to change it manually as the button state changes. One way to do this would be to subclass UIButton and add a target/action on it for the relevant control events. In your case, you would listen to UIControlEventTouchDownto know when to change the background colour to your chosen 'highlight' colour, and UIControlEventTouchDragExitand UIControlEventTouchUpInside to know when to revert back to the normal state background colour.
Here's an existing implementation if you want to save time: https://github.com/TakeScoop/SwiftyButton
Swift 3
For anyone doing it programatically:
var button = UIButton(type: .system)
button.tintColor = UIColor.blue
I'm trying to make a button that will change the background color to a random color. So far I have:
func randomCGFloat() -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UInt32.max)}
extension UIColor {
static func randomColor() -> UIColor {
let r = randomCGFloat()
let g = randomCGFloat()
let b = randomCGFloat()
// If you wanted a random alpha, just create another
// random number for that too.
return UIColor(red: r, green: g, blue: b, alpha: 1.0)
}
}
All of this goes outside the view controller because 'extension' is not allowed inside the view controller and must be at file scope.
Then I have this inside the view controller:
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.randomColor()
For my action button:
#IBAction func changeColor(sender: UIButton) {}
So far the app boots up with a random color. I don't know how to make the action button change the background color to a new random color because background color is outside the scope of my action. I can't put the action outside of the view controller class. The button has to generate a new random color and update the background color.
As long as changeColor is in your view controller, you can just do
#IBAction func changeColor(sender: UIButton) {
self.view.backgroundColor = UIColor.randomColor()
}
and then you have to connect a touch event of your button (say, touchUpInside) to the action. You can do that in Interface Builder (easy) or in code (trickier, but equally easy when you get the hang of it).
I am looking for a solution to this problem that does NOT require using images/PNGs. I am looking for a way to remove the UIButton's blue background color when it's in selected state, and I just cannot find a way to do that without using images. I am basically trying to do something like that in case of a UITableViewCell:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
I had this same issue and I resolve it by changing the UIButton type from "System" to "Custom". The blue background color does not show up in selected state when it is a "Custom" type.
Unfortunately I'm away from my test machine at the moment, but there are two things you could try.
First would be to set the following property:
button.adjustsImageWhenHighlighted = NO;
Or uncheck "Highlight adjusts image" in Interface Builder.
If that doesn't work like you expect it to, you can deselect the button in the action you tied it to, like so:
- (IBAction)yourButtonAction:(id)sender {
[sender setHighlighted:NO];
}
Change the alpha of the tintColor to zero, works if iOS is 5.0 or later
UIColor *color = [[UIColor alloc] initWithRed:0.0 green:0.0 blue:0.0 alpha:0.0];
button.tintColor = color;
Very simple, in storyBoard, select your UIButton and open attribute inspector. Now scroll down to View section and change Tint property to Clear Color or any specific color if u want.
UIButton also with custom type, we can set it in xcode as-
OR
By programmatically as-
let customButton = UIButton(type: .custom)
customButton.setTitle("this is Button", for: .normal)
customButton.setTitleColor(UIColor.blue, for: .normal)
customButton.frame = CGRect(x: 15, y: 50, width: 300, height: 500)
self.view.addSubview( customButton)
Now there is no more UIButton's blue background color
Changed UIButton type to Custom in IB worked for me.
Not a direct answer to OP's question but to remove this colour in a UIButton subclass you can do this:
override func layoutSubviews() {
super.layoutSubviews()
tintColor = .clear
}
What did it for me was changing the button.tintColor in the highlighted state. This is swift 3, iOS 10
override public var isHighlighted: Bool {
didSet {
self.tintColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1.0)
}
}
Or you can do the same in the interface builder
Choose button state
Choose button tint color
Swift Version
extension UIButton {
override public var highlighted: Bool {
didSet {
// clear background color when selected
self.layer.backgroundColor = .None
}
}
}
From iOS 15 onward, UIButton has property configuration. You can set clear color to property baseBackfroundColor to remove background color of UIButton in selected mode.
var config = UIButton.Configuration.plain()
config.baseBackgroundColor = .clear
button.configuration = config
Use...
[myButton setAdjustsImageWhenHighlighted:FALSE];
Not sure if this is the best way. But you could have an invisible button or view ontop of the actual button then recognize when the top button/view has been clicked.