How to save a Color in the #AppStorage in SwiftUi - swift

I want to save a Color value in the #AppStorage but I get an error. How can I fix it?
#AppStorage ("selectedColor") var selectedColor: Color = .teal

save color as string
#AppStorage ("selectedColor") var selectedColor: String = ""
create a function that transforms the color into a string
func updateCardColorInAppStorage(color: Color)-> String {
let 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 "\(red),\(green),\(blue),\(alpha)"
}
and String to Color
if (cardColor != "" ) {
let rgbArray = cardColor.components(separatedBy: ",")
if let red = Double (rgbArray[0]), let green = Double (rgbArray[1]), let blue = Double(rgbArray[2]), let alpha = Double (rgbArray[3]){ bgColor = Color(.sRGB, red: red, green: green, blue: blue, opacity: alpha)
}

Related

black color in function always, why?

I want my text to get random color, for that I made a function but I do get always black color, this function should return a random color for me.
struct ContentView: View {
#State var colorOfText = randomColorFunction()
var body: some View {
Text("Hello, world!").font(Font.largeTitle.bold()).foregroundColor(colorOfText)
}
}
func randomColorFunction() -> Color {
let redValue = UInt8.random(in: 0...255)
let greenValue = UInt8.random(in: 0...255)
let blueValue = UInt8.random(in: 0...255)
print(redValue.description, greenValue.description, blueValue.description)
return Color(red: Double(redValue/255), green: Double(greenValue/255), blue: Double(blueValue/255))
}
You need to change the return of randomColorFunction to this:
return Color(red: Double(redValue)/255.0, green: Double(greenValue)/255.0, blue: Double(blueValue)/255.0)
your solution did not work, because the result of the division always return Int and it causes to be 0 or 1 that means black color or white color
Your code is creating UInt8 values, and dividing them by the int value of 255. The result will always be an integer of 0 or 1. (and the odds are it will be 0 about 255 out of 256 times.)
You need to either use Double.random(in: 0.0...1.0) as suggested by Vadian, or cast your values to doubles:
let redValue = Double(Int.random(in: 0...255))
let greenValue = Double(Int.random(in: 0...255))
let blueValue = Double(Int.random(in: 0...255))
print(redValue.description, greenValue.description, blueValue.description)
return Color(
red: Double(redValue/255.0),
green: Double(greenValue/255.0),
blue: Double(blueValue/255.0))

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

How to convert Color Literal to cgColor in the Swift?

var CodeBackground = #colorLiteral(red: 0.1294117647, green: 0.1294117647, blue: 0.1960784314, alpha: 1)
cells?.layer.borderColor = //... how can i set this color literal to cgColor?
As I know how to convert that UIColor to cgColor in the Swift
as example
UIColor.black.cgColor
Bingo, but what about Color Literal to cgColor in the Swift
Thank you.
As, You already know the simpler way of using colorLiteral as cgcolor, I'll jump to the other way of doing that...
For that you need a Custom Function which gets the color-value(red , green , blue) from the colorLiteral , which is as below
extension UIColor {
func rgb() -> (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 = Int(fAlpha)
_ = (iAlpha << 24) + (iRed << 16) + (iGreen << 8) + iBlue
return (red:iRed, green:iGreen, blue:iBlue, alpha:iAlpha)
} else {
// Could not extract RGBA components:
return nil
}
}
}
//It's more convenient to use function in `UIColor` extension
Now , after this function created you can convert colorliteral into cgColor as below...
let CodeBackground = #colorLiteral(red: 0.1294117647, green: 0.1294117647, blue: 0.1960784314, alpha: 1)
let rgblit = CodeBackground.rgb()
let Converted_cgColor = CGColor(srgbRed: CGFloat(integerLiteral: rgblit!.red), green: CGFloat(integerLiteral: rgblit!.green), blue: CGFloat(integerLiteral: rgblit!.blue), alpha: CGFloat(integerLiteral: rgblit!.alpha))
You can directly use Converted_cgColor like
cells?.layer.borderColor = Converted_cgColor
HOPE IT HELPS

Convert UIColor initialization to Color Literal Xcode

I have multiple different UIColor objects. Some of them are initialized by a constructor some of them are shown as color literals.
static let optionsHeader = UIColor([ ]) // XCode is showing a color rect.
static let optionButtonSelected = UIColor(red: 0.865, green: 0.804, blue: 0.0, alpha: 1.0)
How can I convert the UIColor.init(...) statements to a color literal.
RGB color literal is same as UIColor initialization:
#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
Or you can select color after typing #colorLiteral().
You can also use extensions to use hex color instead of inputting rgba values
extension UIColor {
convenience init(hexString: String, alpha: CGFloat = 1.0) {
let hexString: String = hexString.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
let scanner = Scanner(string: hexString)
if (hexString.hasPrefix("#")) {
scanner.scanLocation = 1
}
var color: UInt32 = 0
scanner.scanHexInt32(&color)
let mask = 0x000000FF
let r = Int(color >> 16) & mask
let g = Int(color >> 8) & mask
let b = Int(color) & mask
let red = CGFloat(r) / 255.0
let green = CGFloat(g) / 255.0
let blue = CGFloat(b) / 255.0
self.init(red:red, green:green, blue:blue, alpha:alpha)
}
func toHexString() -> String {
var r:CGFloat = 0
var g:CGFloat = 0
var b:CGFloat = 0
var a:CGFloat = 0
getRed(&r, green: &g, blue: &b, alpha: &a)
let rgb:Int = (Int)(r*255)<<16 | (Int)(g*255)<<8 | (Int)(b*255)<<0
return String(format:"#%06x", rgb)
}
}
Then you can code it with:
self.backgroundColor = UIColor(hexString: "#4A4A4A")

Having Trouble with Random Numbers in Swift

I am trying to generate random background colors to display to a user when they press a button on the screen. I have an immutable array of UIColor items and I have made a mutable copy to manipulate. When a random color is generated, that color is then returned and removed from the mutable copy of the array to prevent consecutive showings of the same color until all colors have been shown. This is supposed to happen until the array's count is 0, and then it recreates the array to repeat the process. However, when I get down to the array having between 2 and 0 items, the loop seems to turn into an infinite loop. What logic am I missing in my code (playground file)?
var currentColorIndexNumber = 0
var newColorIndexNumber = 0
let colorsArray = [
UIColor(red: 90/255.0, green: 187/255.0, blue: 181/255.0, alpha: 1.0), //teal color
UIColor(red: 222/255.0, green: 171/255.0, blue: 66/255.0, alpha: 1.0), //yellow color
UIColor(red: 223/255.0, green: 86/255.0, blue: 94/255.0, alpha: 1.0), //red color
UIColor(red: 239/255.0, green: 130/255.0, blue: 100/255.0, alpha: 1.0), //orange color
UIColor(red: 77/255.0, green: 75/255.0, blue: 82/255.0, alpha: 1.0), //dark color
UIColor(red: 105/255.0, green: 94/255.0, blue: 133/255.0, alpha: 1.0), //purple color
UIColor(red: 85/255.0, green: 176/255.0, blue: 112/255.0, alpha: 1.0), //green color
]
var mutableColorsArray: [AnyObject] = colorsArray
func randomNumber() -> Int {
// avoid repeating random integers
while currentColorIndexNumber == newColorIndexNumber {
var unsignedArrayCount = UInt32(mutableColorsArray.count)
var unsignedRandomNumber = arc4random_uniform(unsignedArrayCount)
newColorIndexNumber = Int(unsignedRandomNumber)
}
currentColorIndexNumber = newColorIndexNumber
return newColorIndexNumber
}
func randomColor() -> UIColor {
var randomIndex = randomNumber()
var randomColor = mutableColorsArray[randomIndex] as UIColor
mutableColorsArray.removeAtIndex(randomIndex)
if mutableColorsArray.count == 0 {
mutableColorsArray = colorsArray
}
return randomColor
}
Try shuffling instead. Something along these lines:
var colorsArray = ["red","green","blue","yellow","purple"]
var currentColorIndexNumber = colorsArray.count
func shuffle<T>(inout array: Array<T>) -> Void {
for index in 0..<colorsArray.count {
let swapLocation = index + Int(arc4random_uniform(UInt32(colorsArray.count - index)))
if index != swapLocation {
swap(&array[swapLocation], &array[index])
}
}
}
func randomColor() -> String {
// shuffle first time through, then every time the list is exhausted
if currentColorIndexNumber >= colorsArray.count - 1 {
// shuffle, but guarantee first color after shuffling
// is not the same as last color from previous round
do {
shuffle(&colorsArray)
} while colorsArray[0] == lastColor
currentColorIndexNumber = -1
lastColor = colorsArray[colorsArray.count-1]
}
currentColorIndexNumber += 1
return colorsArray[currentColorIndexNumber]
}
for i in (5*colorsArray.count) {
print("\(randomColor()) ")
if i % colorsArray.count == 0 {
println()
}
}
I have had good results with
func randomObject(array: [AnyObject]) -> AnyObject {
return array[Int(arc4random_uniform(UInt32(array.count)))]
}
To enumerate all of the elements in random order, just use a shuffle function as the one below, use the elements of the shuffled array in order and re-shuffle the array once it is exhausted.
func shuffleArray<T>(array: Array<T>) -> Array<T> {
for var i = array.count - 1; i > 0; i-- {
var j = Int(arc4random_uniform(UInt32(i-1)))
swap(&array[i], &array[j])
}
return array
}