Comparing 2 UIColor(s) - ios

This must have been asked before, but I cannot find a suitable reference. I have found this question, but that compares three numbers with each other.
I am trying to compare 2 UIColor(s) to avoid duplication. Each color is referenced in r, g, b, alpha. I form the colors so I can control number formatting.
What would be the appropriate way to handle this?
All help appreciated.

If you are creating all color the same way you can just use ==.
If your colors are in different color spaces and you just want to compare their RGBA value use the following:
extension UIColor {
func equals(_ rhs: UIColor) -> Bool {
var lhsR: CGFloat = 0
var lhsG: CGFloat = 0
var lhsB: CGFloat = 0
var lhsA: CGFloat = 0
self.getRed(&lhsR, green: &lhsG, blue: &lhsB, alpha: &lhsA)
var rhsR: CGFloat = 0
var rhsG: CGFloat = 0
var rhsB: CGFloat = 0
var rhsA: CGFloat = 0
rhs.getRed(&rhsR, green: &rhsG, blue: &rhsB, alpha: &rhsA)
return lhsR == rhsR &&
lhsG == rhsG &&
lhsB == rhsB &&
lhsA == rhsA
}
}
For instance:
let white1 = UIColor.white
let white2 = UIColor(colorLiteralRed: 1, green: 1, blue: 1, alpha: 1)
white1 == white2 //false
white1.cgColor == white2.cgColor //false
white1.equals(white2) //true

If you initialize as UIColor, you should be able to compare the colors to each other easily:
import UIKit
let myFirstColor = UIColor.red
let mySecondColor = UIColor.red
let myThirdColor = UIColor(colorLiteralRed: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
let iosWhite = UIColor.white
let myWhite = UIColor(white: 1.0, alpha: 1.0)
myFirstColor == mySecondColor //True
myFirstColor == myThirdColor //True
iosWhite == myWhite // True
From comments, there edge cases. I think these are all grays black, white and clear. To compensate, you can create your own grays and compare to it:
let myOtherWhite = UIColor(colorLiteralRed: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
which is not equal to UIColor.white
That said, it is easy to find the edge cases on playground:

Related

Supported default light/dark mode colors for Color vs UIColor

I'm trying to use Apple’s built in colors (UIColor.label, UIColor.secondaryLabel, etc), but I can't seem to find their Color equivalent. Since I can't use them as a Color, I can't use them in my SwiftUI code. Is there any way to use these colors in SwiftUI?
I was able to modify some code I found here to make solution. Not the best solution in the world, but it appears to work.
extension Color {
static var label = Color.from(uicolor: .label)
static func from(uicolor: UIColor) -> Color {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
uicolor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return Color(red: Double(red), green: Double(green), blue: Double(blue)).opacity(Double(alpha))
}
}
Usage:
Text("Test").color(.label)

Is it possible to get color name in swift

I am trying to get color name from UIButton in swift instead of value is there any way to do that. Thanks
I am using tintColor to set value as well to get value
clickButton.tintColor = UIColor.blue
var color = clickButton.tintColor
when I am printing color value I get (UIExtendedSRGBColorSpace 0 0 1 1) is there anyway I can get blue instead of value
Add this extension to your project
extension UIColor {
var name: String? {
switch self {
case UIColor.black: return "black"
case UIColor.darkGray: return "darkGray"
case UIColor.lightGray: return "lightGray"
case UIColor.white: return "white"
case UIColor.gray: return "gray"
case UIColor.red: return "red"
case UIColor.green: return "green"
case UIColor.blue: return "blue"
case UIColor.cyan: return "cyan"
case UIColor.yellow: return "yellow"
case UIColor.magenta: return "magenta"
case UIColor.orange: return "orange"
case UIColor.purple: return "purple"
case UIColor.brown: return "brown"
default: return nil
}
}
}
Now you can write
print(UIColor.red.name) // Optional("red")
You cannot get the "human-readable" name of a UIColor by using a built-in. However you can get the RGB values, as described in this post.
If you really want to get the name of the color, you can build your own dictionary, as #BoilingFire pointed out in their answer:
var color = clickButton.tintColor! // it is set to UIColor.blue
var colors = [UIColor.red:"red", UIColor.blue:"blue", UIColor.black:"black"] // you should add more colors here, as many as you want to support.
var colorString = String()
if colors.keys.contains(color){
colorString = colors[color]!
}
print(colorString) // prints "blue"
You can use this extension to get name of color created via Color Assets in XCode.
extension UIColor {
/// Name of color. Only colors created with XCode Color Assets will return actual name, colors created programatically will always return nil.
var name: String? {
let str = String(describing: self).dropLast()
guard let nameRange = str.range(of: "name = ") else {
return nil
}
let cropped = str[nameRange.upperBound ..< str.endIndex]
if cropped.isEmpty {
return nil
}
return String(cropped)
}
}
Result:
From iOS 14.0+ you can also use https://developer.apple.com/documentation/uikit/uicolor/3600314-accessibilityname
UIColor.systemRed.accessibilityName // returns "Red"
Swift 5 and above iOS14
Create an extension for UIColor
extension UIColor {
convenience init(_ r: Double,_ g: Double,_ b: Double,_ a: Double) {
self.init(red: CGFloat(r/255), green: CGFloat(g/255), blue: CGFloat(b/255), alpha: CGFloat(a))
}
convenience init(hex: String) {
let scanner = Scanner(string: hex)
scanner.scanLocation = 0
var rgbValue: UInt64 = 0
scanner.scanHexInt64(&rgbValue)
let r = (rgbValue & 0xff0000) >> 16
let g = (rgbValue & 0xff00) >> 8
let b = rgbValue & 0xff
self.init(
red: CGFloat(r) / 0xff,
green: CGFloat(g) / 0xff,
blue: CGFloat(b) / 0xff, alpha: 1
)
}
func getRGBAComponents() -> (red: Int, green: Int, blue: Int, alpha: Int)?
{
var fRed : CGFloat = 0
var fGreen : CGFloat = 0
var fBlue : CGFloat = 0
var fAlpha: CGFloat = 0
if self.getRed(&fRed, green: &fGreen, blue: &fBlue, alpha: &fAlpha) {
let iRed = Int(fRed * 255.0)
let iGreen = Int(fGreen * 255.0)
let iBlue = Int(fBlue * 255.0)
let iAlpha = 1
return (red:iRed, green:iGreen, blue:iBlue, alpha:iAlpha)
} else {
// Could not extract RGBA components:
return nil
}
}
class func colorWithRGB(r: CGFloat, g: CGFloat, b: CGFloat, alpha: CGFloat = 1.0) -> UIColor {
return UIColor(red: r/255.0, green: g/255.0, blue: b/255.0, alpha: alpha)
}
convenience init(red: Int, green: Int, blue: Int) {
assert(red >= 0 && red <= 255, "Invalid red component")
assert(green >= 0 && green <= 255, "Invalid green component")
assert(blue >= 0 && blue <= 255, "Invalid blue component")
self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
}
convenience init(rgb: Int) {
self.init(
red: (rgb >> 16) & 0xFF,
green: (rgb >> 8) & 0xFF,
blue: rgb & 0xFF
)
}
}
Use like below Code
let RGBArray = YOUR_RGB_COLOR?.components(separatedBy: ",")
let _color = UIColor(red:Int(RGBArray?[0] ?? "0") ?? 255 , green: Int(RGBArray?[1] ?? "0") ?? 255, blue: Int(RGBArray?[2] ?? "0") ?? 255)
if #available(iOS 14.0, *) {
let mString = _color.accessibilityName
print(mString)
}
OUTPUT:
Red
I don't think it's possible but you could build your own dictionnary and search for the key that corresponds to that color object.
Not any color would have a name anyways.
var colors = ["blue": UIColor.blue, ...]
Swift 5.5
Let's assume you have a variable Orange of type UIColor.
var orange: UIColor = UIColor(displayP3Red: 1, green: 0.5, blue: 0, alpha: 1)
You can get the color name by:
var colorName: String {
orange.accessibilityName
}
Hope this helped. Cheers
An extencion for class Color in SwiftUI can be :
extension Color {
var name: String? {
let description = self.description
let firstOccurenceIndex = description.firstIndex(of: "\"") ?? description.startIndex
let startIndex = description.index(firstOccurenceIndex, offsetBy: 1)
let suffix = description.suffix(from: startIndex)
let lastOccurenceIndex = suffix.firstIndex(of: "\"") ?? description.endIndex
let name = suffix.prefix(upTo: lastOccurenceIndex)
return String(name)
}
}

Random number corresponding to array of UIColors- ERROR

I have a function that creates a CGRect and I am trying to assign a random color to each of them.
I create the colors as variables with the type UIColor and then put them into an array called colors. Then, I create a random number generator and call it when defining the background color of the CGRect, but I get the error:
Cannot call value of non-function type "[UIColor}"
Why is this? Here is my code:
func addBox(location: CGRect) -> UIView {
let newBox = UIView(frame: location)
let red = UIColor(red: (242.0/255.0), green: (186.0/255.0), blue: (201.0/255.0), alpha: 1.0)
let green = UIColor(red: (186.0/255.0), green: (242.0/255.0), blue: (216.0/255.0), alpha: 1.0)
let yellow = UIColor(red: (242.0/255.0), green: (226.0/255.0), blue: (186.0/255.0), alpha: 1.0)
let blue = UIColor(red: (186.0/255.0), green: (216.0/255.0), blue: (242.0/255.0), alpha: 1.0)
let colors = [red, green, yellow, blue]
let randomNum:UInt32 = arc4random_uniform(4)
newBox.backgroundColor = UIColor(colors(randomNum))
hView.insertSubview(newBox, at: 0)
return newBox
}
If anyone could solve this that would be amazing. Any help would be immensely appreciated!! Thanks a ton in advance.
This:
newBox.backgroundColor = UIColor(colors(randomNum))
should be:
newBox.backgroundColor = colors[randomNum]
colors is an array of UIColor. You just need one element from the array.
You should also change:
let randomNum:UInt32 = arc4random_uniform(4)
to:
let randomNum = Int(arc4random_uniform(colors.count))
This way if you add more colors to the array, you don't need to adjust this line. It makes your code less error prone.

How to loop through array and start again if the array is at the end?

I have an array of colors, that I want to apply to uitableviewcells in iOS.
let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
cell.backgroundColor = colorPalet[indexPath.row]
The problem is, then when indexPath.row is greater then the colorPalet array, it will crash, because there is no more entries in the array. How to start iteratie again through the array if it is at the end of the array in Swift?
you can use modulo:
cell.backgroudColor = colorPalet[indexPath.row % colorPalet.count]
for index in 0..array.count {
//Do stuff here
if (index == array.count -1)
{
index = 0
}
}
You can use something like this:
let index = indexPath.row%4
cell.something = colorPalet[index]
Make colorPalet an instance variable. You can just move the code below to the top of the class:
let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
That way you're not creating an array of colors for each cell you configure. Then use the modulo (`%) Code in ROC's answer:
cell.backgroudColor = colorPalet[indexPath.row % colorPalet.count]
The accepted answer already covers the specific situation of the OP (cell colors in a table view), whereas this answer will approach the more general question title:
How to loop through array and start again if the array is at the end?
The modulo operation naturally comes to mind,
truncatedIndex = runningIndexDividend % divisor
But what if we're to use this in a long running application, where the runningIndexDividend needlessly increase to values much larger than the divisor (possibly, in a theoretic contrived situation, even leading to integer overflow ...)? For such a case, an alternative, mainly to tap into the Sequence neatness of Swift, is to use an on-the-fly generating sequence: one which lazily constructs its next element upon demand.
Using the global sequence(state:next:) function
For the case of constructing a (infinite) sequence which repeatedly traverses a given array ("joining" the head with the tail), you could make use of the global sequence(state:next:) function.
E.g., applied to your example (here storing the colorPalet as a static member of ColorSettings utility class, just know the possible non-thread safety if using static properties in threaded applications):
class ColorSettings {
private static let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
static let colorSequence = sequence(
state: 1,
next: { (idx: inout Int) -> UIColor? in
guard colorPalet.count > 0 else { return nil }
defer { idx == colorPalet.count ? (idx = 1) : (idx += 1) }
/* alternatively (loose clarity/semantics to gain brevity)
defer { idx = idx % colorPalet.count + 1 } */
return colorPalet[idx-1]
})
}
Example "usage" (not really intended for this application)
// example usage
let numberOfRowsInSection = 7
for (row, color) in zip(0..<numberOfRowsInSection,
ColorSettings.colorSequence) {
// ...
print(row, color)
} /* 0 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
1 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1
2 UIExtendedSRGBColorSpace 0.00784314 0.811765 1 1
3 UIExtendedSRGBColorSpace 0.564706 0.6 0.65098 1
4 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
5 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1
6 UIExtendedSRGBColorSpace 0.00784314 0.811765 1 1 */
Note that the state will not be saved between two separate traversals of colorSequence. I.e., if copying the loop above and applying elsewhere, the first state will always correspond to the first color.
Also beware that when constructing an infinitely generating sequence as the one above, the sequence can naturally not terminate by itself (no nil return, apart from the empty colorPalet array case). Hence its practical use will mostly be in conjunction with a finite sequence with use of zip as above.
Using an external state property with AnyIterator
If you'd rather keep the end state in one traversal as a starting point for the subsequent one (not resetting it, as above), you could use an approach similar to the one above, but using a help state property combined with AnyIterator:
class ColorSettings {
private static let colorPalet = [
UIColor(red: 255.0/255.0, green: 159.0/255.0, blue: 112.0/255.0, alpha: 1),
UIColor(red: 81.0/255.0, green: 218.0/255.0, blue: 168.0/255.0, alpha: 1),
UIColor(red: 2.0/255.0, green: 207.0/255.0, blue: 255.0/255.0, alpha: 1),
UIColor(red: 144.0/255.0, green: 153.0/255.0, blue: 166.0/255.0, alpha: 1)
]
private static var idx: Int = 1
static let colorIterator: AnyIterator<UIColor> = AnyIterator {
guard colorPalet.count > 0 else { return nil }
defer { idx == colorPalet.count ? (idx = 1) : (idx += 1) }
return colorPalet[idx-1]
}
}
Example usage:
// first traversal
for (i, color) in zip(0..<2, ColorSettings.colorIterator) {
// ...
print(i, color)
} /* 0 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
1 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1 */
// state from previous traversal will be used
// to decide starting state here, in next
for (i, color) in zip(0..<4, ColorSettings.colorIterator) {
// ...
print(i, color)
} /* 0 UIExtendedSRGBColorSpace 0.00784314 0.811765 1 1
1 UIExtendedSRGBColorSpace 0.564706 0.6 0.65098 1
2 UIExtendedSRGBColorSpace 1 0.623529 0.439216 1
3 UIExtendedSRGBColorSpace 0.317647 0.854902 0.658824 1 */

Using Extension for Converting Hex to UIColor [duplicate]

This question already has answers here:
How to use hex color values
(39 answers)
Closed 8 years ago.
I am trying to change the background color of TopScoreContainer to a lighter shade of green. I do not want to use greenColor() . Here is the line of code:
self.TopScoreContainer.backgroundColor = UIColor.greenColor()
Is it possible to substitute in a hexadecimal number or RGB value instead of greenColor() ? Thanks.
let myCustomColorHSBa = UIColor(hue: 120/360, saturation: 0.25 , brightness: 1.0 , alpha: 1)
let myCustomColorRGBa = UIColor(red: 191/255, green: 1, blue: 191/255, alpha: 1)
using it as an extension read-only computed var:
Read-Only Computed Properties
A computed property with a getter but no setter is known as a
read-only computed property. A read-only computed property always
returns a value, and can be accessed through dot syntax, but cannot be
set to a different value.
NOTE
You must declare computed properties—including read-only computed
properties—as variable properties with the var keyword, because their
value is not fixed. The let keyword is only used for constant
properties, to indicate that their values cannot be changed once they
are set as part of instance initialization.
You can simplify the declaration of a read-only computed property by
removing the get keyword and its braces:
extension UIColor {
var lightGreen: UIColor {
return UIColor(red: 191/255, green: 1, blue: 191/255, alpha: 1)
}
}
let lightGreen = UIColor().lightGreen
or you can also create your own htmlColor input as follow:
update: Xcode 7.2 • Swift 2.1.1
extension String {
subscript(range: Range<Int>) -> String {
return range.startIndex < 0 || range.endIndex > characters.count ? "Out of Range" : substringWithRange(Range(start: startIndex.advancedBy(range.startIndex),end: startIndex.advancedBy(range.endIndex)))
}
var hexaCGFloat: CGFloat {
return CGFloat(strtoul(self, nil, 16))
}
}
extension UIColor {
convenience init(htmlColor: String, alpha: Double) {
self.init(red: htmlColor[1...2].hexaCGFloat / 255.0, green: htmlColor[3...4].hexaCGFloat / 255.0, blue: htmlColor[5...6].hexaCGFloat / 255.0, alpha: CGFloat(alpha) )
}
convenience init(r: Int, g:Int , b:Int , a: Int) {
self.init(red: CGFloat(r)/255, green: CGFloat(g)/255, blue: CGFloat(b)/255, alpha: CGFloat(a)/255)
}
}
let myColor = UIColor(r: 255 , g: 0, b: 0, a: 255)
let myHtmlWebColor = UIColor(htmlColor: "#bfffbf", alpha: 1.0)

Resources