How to convert UIColor to SwiftUI‘s Color - swift

I want to use a UIColor as foregroundcolor for an object but I don’t know how to convert UIColor to a Color
var myColor: UIColor
RoundedRectangle(cornerRadius: 5).foregroundColor(UIColor(myColor))

Starting with beta 5, you can create a Color from a UIColor:
Color(UIColor.systemBlue)

Both iOS and macOS
Color has a native initializer for it that takes an UIColor or NSColor as an argument:
Color(.red) /* or any other UIColor/NSColor you need INSIDE parentheses */
DO NOT call Color(UIColor.red) explicitly !!!. This will couple your SwiftUI code to the UIKit. Instead, just call Color(.red) That will infer the correct module automatically.
Also, Note this difference:
Color.red /* this `red` is SwiftUI native `red` */
Color(.red) /* this `red` is UIKit `red` */
Note that:
Color.red and UIColor.red are NOT same! They have different values and look different with each other. So DON'T assume this worth nothing
These are equal instead: SwiftUI.Color.Red == UIKit.UIColor.systemRed
Also, You can check out How to get RGB components from SwiftUI.Color
Extension
You can implement a custom variable for it to make it more like cgColor and ciColor
extension UIColor {
/// The SwiftUI color associated with the receiver.
var suColor: Color { Color(self) }
}
so it would be like:
UIColor.red // UIKit color
UIColor.red.suColor // SwiftUI color
UIColor.red.cgColor // Core graphic color
UIColor.red.ciColor // Core image color
Note: Click here to see How to convert SwiftUI.Color to UIColor

Using two helper extensions:
To extract components from UIColor:
extension UIColor {
var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return (red, green, blue, alpha)
}
}
To init with UIColor:
extension Color {
init(uiColor: UIColor) {
self.init(red: Double(uiColor.rgba.red),
green: Double(uiColor.rgba.green),
blue: Double(uiColor.rgba.blue),
opacity: Double(uiColor.rgba.alpha))
}
}
Usage:
Color(uiColor: .red)

In Swift UI custom colors with a convenient extension:
extension UIColor {
struct purple {
static let normal = UIColor(red:0.043, green:0.576 ,blue:0.588 , alpha:1.00)
static let light = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
static let dark = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
}
struct gray {
static let normal = UIColor(red:0.5, green:0.5 ,blue:0.5 , alpha:1.00)
static let dark = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
}
}
Wrapping Color of SwiftUI:
extension UIColor {
var toSUIColor: Color {
Color(self)
}
}
and using this:
var body: some View {
Text("Hello World")
.foregroundColor(Color(UIColor.purple.normal))
.background(Color(UIColor.gray.normal))
// with wrap
//.foregroundColor(UIColor.purple.normal.toSUIColor)
//.background(UIColor.gray.normal.toSUIColor)
}

I'm a really old hobbyist. Here is one way that works for me. Yes, I do use globals for reusable statements in a Constant.swift file. This example is inline so that it is easier to see. I do not say this is the way to go, it is just my old way.
Screenshot (27k)
import SwiftUI
// named color from the developer's pallet
let aluminumColor = Color(UIColor.lightGray)
// a custom color I use often
let butterColor = Color.init(red: 0.9993399978,
green: 0.9350042167,
blue: 0.5304131241)
// how I use this in a SwiftUI VStack:
Text("Fur People")
.font(.title)
.foregroundColor(aluminumColor)
.shadow(color: butterColor, radius: 4, x: 2, y: 2)
.minimumScaleFactor(0.75)

Create an extension like this:
extension Color {
static let someColor = Color(UIColor.systemIndigo) // << Select any UIColor
}
Usage:
struct ContentView: View {
var body: some View {
Rectangle()
.frame(width: 100, height: 100)
.foregroundColor(.someColor)
}
}

Related

How to convert a UIColor to a black and white UIColor

I am setting the background color of my label, but I would like to have the color be the black and white UIColor instead of the original UIColor.
self.MyLabel.backgroundColor = self.selectedColors.color
Looks like you'll need to convert your colour to grayscale.
While you can do this by averaging the R, G and B components of the colour, apple actually provide a nice method to grab the grayscale value:
func getWhite(_ white: UnsafeMutablePointer<CGFloat>?,
alpha: UnsafeMutablePointer<CGFloat>?) -> Bool
So to use this, you would first extract the grayscale colour and then init a new UIColor:
let originalColor = self.selectedColors.color
var white: CGFloat = 0
var alpha: CGFloat = 0
guard originalColor.getWhite(&white, alpha: &alpha) else {
// The color couldn't be converted! Handle this unexpected error
return
}
let newColor = UIColor(white: white, alpha: alpha)
self.MyLabel.backgroundColor = newColor
By thanks of #Sam answer, I write an extension for UIColor:
extension UIColor {
var grayScale: UIColor? {
var white: CGFloat = 0
var alpha: CGFloat = 0
guard self.getWhite(&white, alpha: &alpha) else {
return nil
}
return UIColor(white: white, alpha: alpha)
}
}
You can use it like this:
var grayScaleColorOfRed = UIColor.red.grayScale ?? UIColor.grey

Can UIColor be initialised with both dark and light mode color?

I am using random pastel colours in my training app (bouncing circles), but when my iPad is in dark mode, the pastels looks very bland. Can I somehow initialise UIColor with two colours? Maybe something like:
UIColor(forLightMode: UIColor, forDarkMode: UIColor)
My current app is creating new colours properly, but they do not change automatically, when I change from dark to light mode. The app is just starting to generate new ones from pastel set.
func makeRandomColor() -> UIColor {
let fullRange : ClosedRange<CGFloat> = 0...255
let pastelRange : ClosedRange<CGFloat> = 127...255
let randomPastelRed = CGFloat.random(in: pastelRange) / 255
let randomPastelGreen = CGFloat.random(in: pastelRange) / 255
let randomPastelBlue = CGFloat.random(in: pastelRange) / 255
let randomRed = CGFloat.random(in: fullRange) / 255
let randomGreen = CGFloat.random(in: fullRange) / 255
let randomBlue = CGFloat.random(in: fullRange) / 255
let randomAlpha = CGFloat.random(in: 0.6...1)
return UIColor.init(dynamicProvider: { traitCollection in
if traitCollection.userInterfaceStyle == .dark {
return UIColor(
red: randomRed,
green: randomGreen,
blue: randomBlue,
alpha: randomAlpha
)
} else {
return UIColor(
red: randomPastelRed,
green: randomPastelGreen,
blue: randomPastelBlue,
alpha: randomAlpha
)
}
})
}
You'd need to listen to traitCollectionDidChange notification and redraw your UI either by calling setNeedsLayout() or similar methods from your UIView or UIViewController. For more Information check Implementing Dark Mode on iOS ~22min
You can do something like this:
var dynamicColor = UIColor {(traitCollection: UITraitCollection) -> UIColor in
if traitCollection.userInterfaceStyle == .dark {
return .white
} else {
return .black
}
}
Taken from a Screencast course on Ray Wenderlich (I'm not affiliated with the website): https://www.raywenderlich.com/3979883-dark-mode-deep-dive

Converting CGFloat, CGFloat, CGFloat into UIColor?

I have an array of colours that look like this...
var purpleShades: [(CGFloat, CGFloat, CGFloat)] = [(186.0/255.0, 85.0/255.0, 211.0/255.0), (147.0/255.0, 112.0/255.0, 219.0/255.0), (138.0/255.0, 43.0/255.0, 226.0/255.0), (148.0/255.0, 0.0/255.0, 211.0/255.0), (153.0/255.0, 50.0/255.0, 204.0/255.0), (139.0/255.0, 0.0/255.0, 139.0/255.0)]
rather than duplicate code was wondering if anyone could help convert it to UIColor, so I can use it for this piece of code.
cell.tintColor = grayShades[Int(index)]
This variation of init might help you
It accepts red, green, blue and alpha as parameters.
Here's a nice extension to UIColor:
extension UIColor {
convenience init(hex: UInt, alpha: CGFloat) {
var red, green, blue: UInt
red = ((hex & 0xFF0000) >> 16)
green = ((hex & 0x00FF00) >> 8)
blue = hex & 0x0000FF
self.init(red: CGFloat(red) / 255, green: CGFloat(green) / 255, blue: CGFloat(blue) / 255, alpha: alpha)
}
}
With that you can write:
let purple = UIColor(hex: 0x9932CC, alpha: 1)
If you have a lot of colours, another extension on UIColor gives you…
extension UIColor {
static let darkOrchid = UIColor(hex: 0x 9932CC, alpha: 1)
static let darkMagenta = UIColor(hex: 0x 8B008B, alpha: 1)
static let indigo = UIColor(hex: 0x 4B0082, alpha: 1)
}
which allows you to say, for example…
cell.tintColor = .darkOrchid

How can I make a Swift enum with UIColor value?

I'm making a drawing app and I would like to refer to my colors through use of an enum. For example, it would be cleaner and more convenient to use Colors.RedColor instead of typing out values every time I want that red color. However, Swift's raw value enums don't seem to accept UIColor as a type. Is there a way to do this with an enum or something similar?
I do it like this (basically using a struct as a namespace):
extension UIColor {
struct MyTheme {
static var firstColor: UIColor { return UIColor(red: 1, green: 0, blue: 0, alpha: 1) }
static var secondColor: UIColor { return UIColor(red: 0, green: 1, blue: 0, alpha: 1) }
}
}
And you use it like:
UIColor.MyTheme.firstColor
So you can have a red color inside your custom theme.
If your color isn't one of those defined by UIColor's convenience method, you can add an extension to UIColor:
extension UIColor {
static var firstColor: UIColor { return UIColor(red: 1, green: 0, blue: 0, alpha: 1) }
static var secondColor: UIColor { return UIColor(red: 0, green: 1, blue: 0, alpha: 1) }
}
// Usage
let myColor = UIColor.firstColor
I use computed properties to solve this problem, this is my code
enum MyColor {
case navigationBarBackgroundColor
case navigationTintCololr
}
extension MyColor {
var value: UIColor {
get {
switch self {
case .navigationBarBackgroundColor:
return UIColor(red: 67/255, green: 173/255, blue: 247/255, alpha: 1.0)
case .navigationTintCololr:
return UIColor.white
}
}
}
}
then I can use MyColor like this:
MyColor.navigationBarBackgroundColor.value
How can I make a Swift enum with UIColor value?
This is how you would literally make an enum with a UIColor value:
import UIKit
final class Color: UIColor, RawRepresentable, ExpressibleByStringLiteral
{
// MARK:- ExpressibleByStringLiteral
typealias StringLiteralType = String
convenience init(stringLiteral: String) {
guard let (a,r,g,b) = Color.argb(hexColor: stringLiteral) else {
assertionFailure("Invalid string")
self.init(red: 0, green: 0, blue: 0, alpha: 0)
return
}
self.init(red: r, green: g, blue: b, alpha: a)
}
// MARK:- RawRepresentable
public typealias RawValue = String
convenience init?(rawValue: RawValue) {
guard let (a,r,g,b) = Color.argb(hexColor: rawValue) else { return nil }
self.init(red: r, green: g, blue: b, alpha: a)
}
var rawValue: RawValue {
return hexString()
}
// MARK:- Private
/// Return color components in range [0,1] for hexadecimal color strings.
/// - hexColor: case-insensitive string with format RGB, RRGGBB, or AARRGGBB.
private static func argb(hexColor: String) -> (CGFloat,CGFloat,CGFloat,CGFloat)?
{
let hexAlphabet = "0123456789abcdefABCDEF"
let hex = hexColor.trimmingCharacters(in: CharacterSet(charactersIn: hexAlphabet).inverted)
var int = UInt32()
Scanner(string: hex).scanHexInt32(&int)
let a, r, g, b: UInt32
switch hex.count {
case 3: (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) // RGB
case 6: (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) // RRGGBB
case 8: (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) // AARRGGBB
default: return nil
}
return (CGFloat(a)/255, CGFloat(r)/255, CGFloat(g)/255, CGFloat(b)/255)
}
private func hexString() -> String {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
return String(format: "#%02X%02X%02X%02X", UInt8(red * 255), UInt8(green * 255), UInt8(blue * 255), UInt8(alpha * 255))
}
assertionFailure("Invalid colour space.")
return "#F00"
}
}
enum Colors: Color {
case red = "#F00"
// case blue = "#F00" // Raw value for enum case is not unique
}
let color3 = Color(rawValue: "#000") // RGB
let color6 = Color(rawValue: "#123456") // RRGGBB
let color8 = Color(rawValue: "#12345678") // AARRGGBB
print(Colors(rawValue:"#F00") as Any) // red
print(Colors(rawValue:"#FF0000") as Any) // red
print(Colors(rawValue:"#FFFF0000") as Any) // red
print(Colors(rawValue:"#ABC") as Any) // nil because it’s not a member of the enumeration
// print(Colors(rawValue:"#XYZ") as Any) // assertion on debug, black on release
print(Colors.red) // red
print(Colors.red.rawValue) // UIExtendedSRGBColorSpace 1 0 0 1
With help from
benhurott/UIColorExtension.md
Swift 3 UIColor utilities for random color and color from hex code
Raw type 'Bool' is not expressible by any literal
This can be done much more succinctly (and should):
extension UIColor
{
static let myColor = UIColor(displayP3Red: 0.0, green: 0.7, blue: 0.0, alpha: 1.0)
}
(Any other method that returns a UIColor is equally suitable, doesn't need to be displayP3Red)
Usage:
let someColor: UIColor = .myColor
Actually I use such implementation, it is very convenience for me because of two reason, first one I can use dex value and another all colors in constant
import UIKit
struct ColorPalette {
struct Gray {
static let Light = UIColor(netHex: 0x595959)
static let Medium = UIColor(netHex: 0x262626)
}
}
extension UIColor {
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(netHex: Int) {
self.init(red: (netHex >> 16) & 0xff, green: (netHex >> 8) & 0xff, blue: netHex & 0xff)
}
}
usage
let backgroundGreyColor = ColorPalette.Gray.Medium.cgColor
If you want to return multiple value then use below code...it's absolutely
working for me....
enum GetDriverStatus : String {
case ClockIn = "Clock In"
case TripStart = "Trip Start"
case BeaconTouchPlant = "Beacon Touch Plant"
case PickUp = "Pick Up"
case BeaconTouchSite = "Beacon Touch Site"
case BeaconLeftSite = "Beacon Left Site"
case DropOff = "Drop Off"
case BreakIn = "Break In"
case BreakOut = "Break Out"
case TripEnd = "Trip End"
case DayEnd = "Day End"
//case ClockOut = "Clock Out"
//Get data from ID
static var allValues: [GetDriverStatus] {
return [
.ClockIn,
.TripStart,
.BeaconTouchPlant,
.PickUp,
.BeaconTouchSite,
.BeaconLeftSite,
.DropOff,
.BreakIn,
.BreakOut,
.TripEnd,
.DayEnd
]
}
//Get Color
var colorAndStatus: (UIColor,String) {
get {
switch self {
case .ClockIn,.TripStart: //Idle
return (UIColor(red: 248/255, green: 39/255, blue: 71/255, alpha: 1.0),"Idle") //dark pink-red
case .BeaconTouchPlant,.PickUp:
return (UIColor(red: 46/255, green: 180/255, blue: 42/255, alpha: 1.0),"Picking up") //Green
case .BeaconTouchSite:
return (UIColor(red: 252/255, green: 172/255, blue: 0/255, alpha: 1.0),"On site") //orange
case .DropOff,.BeaconLeftSite:
return (UIColor(red: 12/255, green: 90/255, blue: 255/255, alpha: 1.0),"Dropping off") //blue
case .BreakIn,.BreakOut:
return (UIColor(red: 151/255, green: 151/255, blue: 151/255, alpha: 1.0),"On break") //warm-grey-two
case .TripEnd:
return (UIColor.black,"Trip end")
case .DayEnd:
return (UIColor.black,"Done for the day")
}
}
}
}
How to use this code
Passing .allvalues["index of your option"] you getting UIColor at 0 position as well as String value as 1 position
GetDriverStatus.allValues[1].colorAndStatus.0 //UIColor.Black
GetDriverStatus.allValues[2].colorAndStatus.1 //"Picking up"
Based on #Jano's answer I made an improvement by using Int as the literal type:
import UIKit
public final class Colors: UIColor {
}
extension Colors: ExpressibleByIntegerLiteral {
public typealias IntegerLiteralType = Int
public convenience init(integerLiteral value: Int) {
let red = CGFloat((value & 0xFF0000FF) >> 24) / 0xFF
let green = CGFloat((value & 0x00FF00FF) >> 16) / 0xFF
let blue = CGFloat((value & 0x0000FFFF) >> 8) / 0xFF
let alpha = CGFloat(value & 0x00FF00FF) / 0xFF
self.init(red: red, green: green, blue: blue, alpha: alpha)
}
}
extension Colors: RawRepresentable {
public typealias RawValue = Int
public var rawValue: RawValue {
return hex
}
public convenience init?(rawValue: RawValue) {
self.init(integerLiteral: rawValue)
}
}
fileprivate extension UIColor {
var hex: 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 red = Int(fRed * 255.0)
let green = Int(fGreen * 255.0)
let blue = Int(fBlue * 255.0)
let alpha = Int(fAlpha * 255.0)
let rgb = (alpha << 24) + (red << 16) + (green << 8) + blue
return rgb
} else {
return 0x000000
}
}
}
public enum MainPalette: Colors {
case red = 0xFF0000ff
case white = 0xFFFFFFFF
}
public enum FeatureXPalette: Colors {
case blue = 0x024F9Eff
// case bluish = 0x024F9Eff // <- Can't do
case red = 0xFF0000ff
}
The advantage is that it doesn't allow duplicate colors (as a true enum) and also I support alpha.
As you can see, you can create multiple enums for different palettes/schemes. In the case you want views to be able to use any palette, you can just add a protocol:
protocol Color {
var color: UIColor { get }
}
extension MainPalette: Color {
var color: UIColor {
return rawValue
}
}
extension FeatureXPalette: Color {
var color: UIColor {
return rawValue
}
}
so that way you can have a function that takes in the protocol:
func printColorEquality(color1: Color, color2: Color) {
print(color1.color == color2.color)
}
let red1: Color = MainPalette.red
let red2: Color = FeatureXPalette.red
printColorEquality(color1: red1, color2: red2)
What I also like to do is add static vars for convenience:
extension MainPalette {
public static var brightRed: UIColor {
return MainPalette.red.color
}
}
that gives you a cleaner api:
view.backgroundColor = MainPalette.brightRed
Naming can be improved: you have to choose if you want a nice convenience api or nice naming for your enums.
This answer is probably late, but for others finding this question.
I was not satisfied with the answers above, since adding colors as UIColors extension is not always what you want, since:
It might not be the best solution from Software architecture perspective.
You can not use the power enums have, e.g. CaseIterable
This is the solution I came up with:
enum PencilColor {
case lightRed
case darkPurple
var associatedColor: UIColor {
switch self {
case .lightRed: return UIColor(red: 67/255, green: 173/255, blue: 247/255, alpha: 1.0)
case .darkPurple: return UIColor(red: 67/255, green: 173/255, blue: 247/255, alpha: 1.0)
}
}
}

UIButton Borders Function Only Gives Back White Borders

I'm trying to create a Button Borders Function in Swift to help style my UI. However whatever RGB values I pass in/initialize the function only creates white borders.
Here is my function:
func buttonsWithBorders(button: UIButton, borderWidth: CGFloat, redcolour: CGFloat , greencolour: CGFloat, bluecolour: CGFloat, alpha: CGFloat?) {
let redcolour : CGFloat = 7.0
var greencolour : CGFloat = 3.0
var bluecolour : CGFloat = 2.0
var alpha: CGFloat = 1.0
var widthOfBorder: CGFloat = borderWidth
var theButtonWithBorders: UIButton
var buttonBorderColour : UIColor = UIColor(red: redcolour, green: greencolour, blue: bluecolour, alpha: alpha)
button.layer.borderWidth = widthOfBorder
return button.layer.borderColor = buttonBorderColour.CGColor
}
And I call it using:
buttonsWithBorders(learnHomeButton, 2.0,2.0, 5.0, 5.0, 1.0)
Also I know that passing in values and initializing them is incorrect but Xcode complaines that I am not initializing before using them otherwise
Any help would be very much appreciated, Cheers
You aren't initializing them. You're declaring entirely new variables with the same names as the parameters you're passing in. Whenever you use let or var you are introducing a brand new variable.
When a new variable is introduced with the same name as another currently in scope, this is known as variable shadowing, and what you have here is an almost textbook case.
A better, more concise implementation of your function might look like this:
func addButtonBorder(button: UIButton, width: CGFloat, red: CGFloat, blue: CGFloat, green: CGFloat, alpha: CGFloat = 1.0) {
button.layer.borderColor = UIColor(red: red, green: green, blue: blue, alpha: alpha).CGColor
button.layer.borderWidth = width
}
I used a different name because buttonsWithBorders implies that one or more buttons will be returned from this function. That does not appear to be your intent. Since you are passing one button in, you could only ever get one out, but "buttons" implies more than one.
If I were going to initialize a lot of buttons with borders, I might do something like this:
extension UIButton {
convenience init(frame: CGRect, borderColor: UIColor, borderWidth: CGFloat = 1.0) {
self.init(frame: frame)
setBorder(borderColor, borderWidth: borderWidth)
}
func setBorder(borderColor: UIColor, borderWidth: CGFloat = 1.0) {
layer.borderWidth = borderWidth
layer.borderColor = borderColor.CGColor
}
}
Then you could say UIButton(frame: frame, borderColor: borderColor, borderWidth: 2.0) to initialize a new button or button.setBorder(borderColor, borderWidth: 2.0) to set the border on an existing button.
UIColor takes a float between 0 and 1. So you want to divide your RGB Values by 255.0
Here is the code I used, that works on playground :
import Foundation
import UIKit
func buttonsWithBorders(button: UIButton, borderWidth: CGFloat,
redcolour:CGFloat, greencolour:CGFloat, bluecolour:CGFloat,
alpha:CGFloat) {
let buttonBorderColour : UIColor = UIColor(red: redcolour, green: greencolour, blue: bluecolour, alpha: alpha)
button.layer.borderWidth = borderWidth
return button.layer.borderColor = buttonBorderColour.CGColor
}
let learnHomeButton = UIButton(frame: CGRect(x: 0, y: 0, width: 50,
height: 50))
buttonsWithBorders(learnHomeButton, 2.0, 177/255.0, 177/255.0,
177/255.0, 1.0)
I edited the code so you can pass the colors to the function as parameters. Hope it helps.
The colour values need to be between 0.0 and 1.0 so you should define them as:
let redcolour : CGFloat = 7.0 / 255.0
var greencolour : CGFloat = 3.0 / 255.0
var bluecolour : CGFloat = 2.0 / 255.0