Swift, SwiftUI - .getRed(&red, green: &green, blue: &blue, alpha: &alpha) - swift

I am following Stanfords' CS193p Developing Apps for iOS online course.
I'm trying to do the Assignment 6 Memorize.pdf.
It says to use this code below ⬇️, but it gives me always white color. Is there a bug somewhere? Please help.
import SwiftUI
struct RGBAColor: Codable, Equatable, Hashable {
let red: Double
let green: Double
let blue: Double
let alpha: Double
}
extension Color {
init(rgbaColor rgba: RGBAColor) {
self.init(.sRGB, red: rgba.red, green: rgba.green, blue: rgba.blue, opacity: rgba.alpha)
}
}
extension RGBAColor {
init(color: Color) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
if let cgColor = color.cgColor {
UIColor(cgColor: cgColor).getRed(&red, green: &green, blue: &blue, alpha: &alpha)
}
self.init(red: Double(red), green: Double(green), blue: Double(blue), alpha: Double(alpha))
}
}
import SwiftUI
struct ContentView: View {
static let rgbaColorRed = RGBAColor(color: Color.red)
static let thisShouldBeRed = Color(rgbaColor: rgbaColorRed)
var body: some View {
Text("Hello, world!")
.padding()
.foregroundColor(ContentView.thisShouldBeRed) // why white here, not red???
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

As the cgColor property's documentation says:
For a dynamic color, like one you load from an Asset Catalog using init(_:bundle:), or one you create from a dynamic UIKit or AppKit color, this property is nil.
Color.red is actually a dynamic color:
A context-dependent red color suitable for use in UI elements.
So Color.red.cgColor is nil, causing the getRed(_:green:blue:alpha:) call to not run, and the red, green, blue, alpha local variables remain 0. So the color you got is not "white", but "transparent".
You can actually create a UIColor directly from Color, without going through CGColor:
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
// note here:
UIColor(color).getRed(&red, green: &green, blue: &blue, alpha: &alpha)
self.init(red: Double(red), green: Double(green), blue: Double(blue), alpha: Double(alpha))

Related

Random numbers - CGFloat

Is there any idea or better approach do it more nice, elegant way ?
extension UIColor {
static var randomColor: UIColor {
.init(
red: CGFloat(Float.random(in: 0 ... 1.0)),
green: CGFloat(Float.random(in: 0 ... 1.0)),
blue: CGFloat(Float.random(in: 0 ... 1.0)),
alpha: 1.0
)
}
}
Rather than …
CGFloat(Float.random(in: 0 ... 1.0))
… you can use:
CGFloat.random(in: 0...1)
Or, in this context, you can let the compiler infer the type:
extension UIColor {
static var randomColor: UIColor {
.init(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1
)
}
}
Randomize color hue
If you want random red, green, and blue components for your random color, go with #Rob's approach. If you want a randomly selected bright saturated color, randomize the hue.
extension UIColor {
static var randomHue: UIColor {
.init(hue: .random(in: 0...1),
saturation: 1, brightness: 1, alpha: 1)
}
static var randomRGB: UIColor {
.init(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1)
}
}
It really depends what mean by "it" in the text describing what you want. Random components tend to yield dull colors.

How to set alpha for an Assets Color in Swift

I just wanted to know how to change the opacity (alpha) of an asset color I have. When I try this UIColor(named: "something", alpha: 0.4), Xcode complains: Extra argument 'alpha' in call.
Is there any way I can modify the opacity of an asset color programmatically?
UIColor, as mentioned by Jasur S., has the withAlphaComponent(_:).
It can be used with any UIColor objects to modify its alpha:
let color = UIColor(named: "something")?.withAlphaComponent(0.5)
Creating custom extensions to cover existing functionality is an arguable good.
You can add this extension for UIColor and easy to use.
extension UIColor {
convenience init?(named: String, alpha: CGFloat) {
if let rgbComponents = UIColor(named: named)?.cgColor.components {
self.init(red: rgbComponents[0], green: rgbComponents[1], blue: rgbComponents[2], alpha: alpha)
} else {
self.init(named: named)
}
}
}
Usage:
let colorWithAlpha = UIColor(named: "Assets Color", alpha: 0.5)
You can set color alpha component when you assign color as follows:
button.backgroundColor = .black.withAlphaComponent(0.5)
You can modify asset color from here
Select that particular asset color and
Drag that opacity indicator in left or right or directly set some values
Use this extension to get the rgb value from the 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)
}
}
Then you can create a new color
let assetColor = UIColor(named: "something")
let (r,g,b,_) = assetColor.rgba
let newColor = UIColor(red:r, green:g, blue:b, alpha: 0.4)

How to get a string from a CGColor MacOS [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am trying to make an app to make it easier to select certain colors and for me to use the NSPasteboard.setString command I need to format the color as a string. Is there a way I can change a CGColor into a string?
Thanks!
Here's a useful extension I made for doing this with CGColor. You can get the RGBA components, as well as convert them back.
Code:
extension CGColor {
/// Components of a color. Contains `rgba`.
struct Components: Codable {
let red: CGFloat
let green: CGFloat
let blue: CGFloat
let alpha: CGFloat
init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
}
init?(rgba: [CGFloat]) {
guard rgba.count == 4 else { return nil }
red = rgba[0]
green = rgba[1]
blue = rgba[2]
alpha = rgba[3]
}
var all: [CGFloat] {
[red, green, blue, alpha]
}
}
var components: Components? {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
_ = NSColor(cgColor: self)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
let components = [red, green, blue, alpha]
return Components(rgba: components)
}
static func create(from components: Components) -> CGColor {
self.init(
red: components.red,
green: components.green,
blue: components.blue,
alpha: components.alpha
)
}
}
Usage:
if let components = CGColor(red: 1, green: 0.2, blue: 0.2, alpha: 1).components {
print(components)
let new = CGColor.create(from: components)
print(new)
}
Prints: Components(red: 1.0, green: 0.2, blue: 0.2, alpha: 1.0)
Prints: <CGColor 0x600003f1d500> [<CGColorSpace 0x600003f1ab80> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; Generic RGB Profile)] ( 1 0.2 0.2 1 )

Swift - why NSColor becomes lighter when rendered

I've created NSWindow and made it's background colour absolutely blue (#0000FF). But when the window is rendered, the colour is "lighter" than it should be (#0F3FFB).
class LilWindow: NSViewController {
override func viewDidLoad() {
self.view.window?.backgroundColor =
NSColor.init(red: 0, green: 0, blue: 1, alpha: 1)
}
Does anyone know why it is happening and how to fix this? (screenshot attached)
Okay, so after a couple of hours fiddling with code and #KenThomases help, I figured out that if you want your RGB colours to looks correctly on NSImages and NSWindows, you must convert it into NSDeviceRGBColorSpace colorspace. To do this I've written a simple function:
func toScreenColor(color:NSColor) -> NSColor {
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
color
.colorUsingColorSpaceName(NSCalibratedRGBColorSpace)!
.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return NSColor(deviceRed: red, green: green, blue: blue, alpha: alpha)
}

How to make a random color with Swift

How I can make a random color function using Swift?
import UIKit
class ViewController: UIViewController {
var randomNumber = arc4random_uniform(20)
var randomColor = arc4random()
//Color Background randomly
func colorBackground() {
// TODO: set a random color
view.backgroundColor = UIColor.yellow
}
}
You're going to need a function to produce random CGFloats in the range 0 to 1:
extension CGFloat {
static func random() -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UInt32.max)
}
}
Then you can use this to create a random colour:
extension UIColor {
static func random() -> UIColor {
return UIColor(
red: .random(),
green: .random(),
blue: .random(),
alpha: 1.0
)
}
}
If you wanted a random alpha, just create another random number for that too.
You can now assign your view's background colour like so:
self.view.backgroundColor = .random()
For Swift 4.2
extension UIColor {
static var random: UIColor {
return UIColor(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0
)
}
}
For Swift 3 and above:
extension CGFloat {
static var random: CGFloat {
return CGFloat(arc4random()) / CGFloat(UInt32.max)
}
}
extension UIColor {
static var random: UIColor {
return UIColor(red: .random, green: .random, blue: .random, alpha: 1.0)
}
}
Usage:
let myColor: UIColor = .random
Make a function to generate random color:
func getRandomColor() -> UIColor {
//Generate between 0 to 1
let red:CGFloat = CGFloat(drand48())
let green:CGFloat = CGFloat(drand48())
let blue:CGFloat = CGFloat(drand48())
return UIColor(red:red, green: green, blue: blue, alpha: 1.0)
}
Now, you can call this function whenever you need random color.
self.view.backgroundColor = getRandomColor()
For random solid colors you can use UIColor HSB initializer and randomize only the hue:
extension UIColor {
static var random: UIColor {
return .init(hue: .random(in: 0...1), saturation: 1, brightness: 1, alpha: 1)
}
}
let color1: UIColor = .random
let color2: UIColor = .random
let color3: UIColor = .random
let color4: UIColor = .random
let color5: UIColor = .random
SwiftUI - Swift 5
import SwiftUI
extension Color {
static var random: Color {
return Color(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1))
}
}
Usage:
let randomColor: Color = .random
With Swift 4.2, you can simplify this by using the new random functions which have been added:
extension UIColor {
static func random () -> UIColor {
return UIColor(
red: CGFloat.random(in: 0...1),
green: CGFloat.random(in: 0...1),
blue: CGFloat.random(in: 0...1),
alpha: 1.0)
}
}
There are more details here.
Swift 4.2 🔸
I'm adding this answer because it uses a different approach, and because many of the previous answers requires additional syntactic sugar, which in my opinion shouldn't be preferred. Vanilla Swift for the win.
extension UIColor {
/**
* Returns random color
* ## Examples:
* self.backgroundColor = UIColor.random
*/
static var random: UIColor {
let r:CGFloat = .random(in: 0...1)
let g:CGFloat = .random(in: 0...1)
let b:CGFloat = .random(in: 0...1)
return UIColor(red: r, green: g, blue: b, alpha: 1)
}
}
Swift 4.2 Extension
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(rgb: Int) {
self.init(
red: (rgb >> 16) & 0xFF,
green: (rgb >> 8) & 0xFF,
blue: rgb & 0xFF
)
}
static func random() -> UIColor {
return UIColor(rgb: Int(CGFloat(arc4random()) / CGFloat(UINT32_MAX) * 0xFFFFFF))
}
}
Usage:
let color = UIColor.random()
Swift 5.1
Make This function and generate Random color.
e.g. view.backgroundColor = random()
func random() -> UIColor {
return UIColor(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0)
}
Using an extension with an inline function to generate randoms
extension UIColor {
static func random() -> UIColor {
func random() -> CGFloat { return .random(in:0...1) }
return UIColor(red: random(),
green: random(),
blue: random(),
alpha: 1.0)
}
}
func anotherGetRandomColor()->UIColor{
let newRed = Double(arc4random_uniform(256))/255.0
let newGreen = Double(arc4random_uniform(256))/255.0
let newBlue = Double(arc4random_uniform(256))/255.0
return UIColor(red: CGFloat(newRed), green: CGFloat(newGreen), blue: CGFloat(newBlue), alpha: 1.0)
}