reverse .label in swift - swift

I want my text to appear .white when in normal mode and .black when in dark mode. How do I do that? .label only makes the text .black in normal and .white in dark mode but I want it the other way around.
Anyone have a solution for that?

let myLabelColor = UIColor(dynamicProvider: { $0.userInterfaceStyle == .dark ? .black : .white })
Since iOS 13, UIColor has an init(dynamicProvider:)
Creates a color object that uses the specified block to generate its color data dynamically.
 https://developer.apple.com/documentation/uikit/uicolor/3238041-init
If you will be creating a lot of dynamic colors, you might want to make a convenience init—that saves you the typing, and your intention is more clear to the reader:
extension UIColor {
/// Creates a color object that responds to `userInterfaceStyle` trait changes.
public convenience init(light: UIColor, dark: UIColor) {
guard #available(iOS 13.0, *) else { self.init(cgColor: light.cgColor); return }
self.init(dynamicProvider: { $0.userInterfaceStyle == .dark ? dark : light })
}
}
Usage: let myLabelColor = UIColor(light: .white, dark: .black)
(Note that you can use any other trait from the provided trait collection. For example, you could return a different color if the size class changes)

In my assets I created a new "Color Set". For chose white for "Any Appearance" and black for "Dark". Then I gave this Image Set a name and called it like so:
text.textColor = UIColor(named: "ImageSet1")

Related

Set Color Dark & Light Mode for label background

class func setColorLightDarkMode() -> UIColor {
let aColor = UIColor(named: "StatusBackGroundColor") ?? .gray
return aColor
}
label.backgroundColor = setColorLightDarkMode()
Added Color Assert for BackGroundColor and set AnyAppearance & DarkAppearance with two different color.
set default set to .gray, how to avoid default value .gray
for setting dark & light mode for background Color
Which is best way to to have making setColorLightDarkMode return type optional ? or UIColor and set ?? .defaultColor

How can you allow for a user changing to dark or light mode with the app open on iOS?

I have updated views in my app to support dark mode by adding
if #available(iOS 12.0, *) {
if self.traitCollection.userInterfaceStyle == .dark {
//Adapt to dark Bg
} else {
//Adapt to light Bg
}
}
Then, to allow for the case where the user backgrounds the app and returns to it after switching mode, I attach an observer in my viewDidLoad
if #available(iOS 12.0, *) {
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
} else {
// Fallback on earlier versions
}
which triggers the function
#available(iOS 12.0, *)
#objc func willEnterForeground() {
if self.traitCollection.userInterfaceStyle == .dark {
print("App moving to foreground - dark")
//Adapt to dark Bg
} else {
print("App moving to foreground - light")
//Adapt to light Bg
}
}
However, self.traitCollection.userInterfaceStyle still gives the old value so a full reload of the view is required to produce the desired update to the interface.
Using UIApplication.didBecomeActiveNotification instead makes no difference.
You don't need all those messy if statements! Just add your colours to your Asset Catalogue and the right one will automatically be selected. This is similar to how you can add x1, x2 and x3 images, and the right one will be selected.
Go to the Asset Catalogue and at the bottom left, click on the plus button, select "New Color Set":
Give the colour a name, and in the property inspector, set "Appearance" to "Any, Dark":
Choose a colour for each appearance:
Finally, use the UIColor(named:) initialiser to initialise the colours and they will automatically change when the device's dark mode settings change:
someView.backgroundColor = UIColor(named: "myColor")
EDIT:
If the colours are only known at runtime, you can use the init(dynamicProvider:) initialiser (iOS 13 only though):
someView.backgroundColor = UIColor {
traits in
if traits.userInterfaceStyle == .dark {
// return color for dark mode
} else {
// return color for light mode
}
}

Mysterious UIColor behaviour with UIView and in General in Swift

Recently I came across an interesting(may be naive) problem regarding UIColor in Swift..
import UIKit
let view = UIView(frame: CGRect(x: 0,
y: 0,
width: 50,
height: 50))
view.backgroundColor = .systemBlue
let a = UIColor.systemBlue
switch a {
case .red:
print("red")
case .systemBlue:
print("blue")
default:
print("unknown")
}
Following code prints "blue" on playground perfectly fine, but changing
let a = UIColor.systemBlue
to
let a = view.backgroundColor ?? .red
prints "unknown" in playground, May someone help what is happening here? I could not resolve it.. Is it something related to value type or reference type at some point?? Please help!!
Printing the two values gives you the explanation:
print(UIColor.systemBlue)
<UIDynamicSystemColor: 0x600000b47880;
name = systemBlueColor
>
print(view.backgroundColor!)
<UIDynamicModifiedColor: 0x60000058bed0;
contrast = normal,
baseColor = <UIDynamicSystemColor: 0x600000b47880;
name = systemBlueColor
>
>
When setting the backgroundColor property, UIKit wraps the color in a private class UIDynamicModifiedColor.
If you compare the resolved colors using the view's traits, you'll get true:
UIColor.systemBlue.resolvedColor(with: view.traitCollection) ==
view.backgroundColor!.resolvedColor(with: view.traitCollection)
The resolved color is an absolute color:
print(UIColor.systemBlue.resolvedColor(with: view.traitCollection))
UIExtendedSRGBColorSpace 0 0.478431 1 1
A color such as UIColor.systemBlue is a dynamic color that might result in different colors, depending on the view's traits, which include factors such as high-contrast mode and dark/light mode.
From the docs of UIColor.systemBlue:
A blue color that automatically adapts to the current trait environment.

Swift: How to access a Switch Statement in a Swift file (error: Statements are not allowed at the top level)?

I am still new to Swift and coding in general and I am trying to create some kind of option for the user to change colored themes.
But I am clueless on how to access a switch statement in a swift file (or how to encapsulate it) and how to access the set variable?
So far I let the user choose a theme in a settings view controller and the name of the theme is saved in UserDefaults in the key "theme".
In a file called themes.swift I have created a switch statement to check for the names. Each case can obviously set a couple of variables I have declared above the switch statement.
But I get the error that "Statements are not allowed at the top level"?
How can I fix this?
And what can I do to let the switch statement run each time a view controller is presented to check for the correct colors or let it run once a new theme is selected and set the variables? I understand the error message but I have no idea on how to fix this.
For instance this is how I have set up the themes.swift file so far:
import UIKit
var theme = UserDefaults.standard.string(forKey: "themes")
var background: UIColor?
var labelColor: UIColor?
var buttonColor: UIColor?
switch theme {
case "Red":
background = UIColor(named: "darkRed")
labelColor = UIColor(named: "labelRed")
buttonColor = UIColor(named: "buttonRed")
case "Blue":
background = UIColor(named: "darkBlue")
labelColor = UIColor(named: "labelBlue")
buttonColor = UIColor(named: "buttonBlue")
default:
return
}
So how can I access those variables?
Besides the top level error, can I just access the variables like I would normally do because they are global variables?
Eg. startButton.setTitleColor(buttonColor, for: .normal) ?
You are getting this error because you have your switch statement just sitting inside some class or struct (it's not clear where you have this code implemented). To fix your error you will need to put that switch inside a function. Perhaps you could create a function called setTheme, like so:
var theme = UserDefaults.standard.string(forKey: "themes")
var background: UIColor?
var labelColor: UIColor?
var buttonColor: UIColor?
func setTheme() {
//First, check to make sure theme is not nil
guard let theme = self.theme else { return }
switch theme {
case "Red":
background = UIColor(named: "darkRed")
labelColor = UIColor(named: "labelRed")
buttonColor = UIColor(named: "buttonRed")
case "Blue":
background = UIColor(named: "darkBlue")
labelColor = UIColor(named: "labelBlue")
buttonColor = UIColor(named: "buttonBlue")
default:
return
}
}
Another option would be to make your UIColor? attributes computed variables. For example:
var background: UIColor? {
guard let theme = self.theme else { return nil }
switch theme {
case "Red": return UIColor(named: "darkRed")
case "Blue": return UIColor(named: "darkBlue")
default: return nil
}
}

How can we use Assets Catalog Color Sets?

I usually use custom UIColors on iOS using extensions with Swift, but now with iOS 11/ Xcode 9 we can create Colors Sets. How can we use them?
Update - Tip
As #Cœur says we can drag&drop de color, and use it like a UIColor object and a possible solution could be use it as a extension:
Or as a constant:
Now I wanna know if we can access them like an UIImage access to an Asset Image or not, like:
UIImage(named: "image-name") -> UIColor(named: "color-name")
UIColor(named: "myColor")
Source: WWDC 2017 Session 237 —— What's New in MapKit
Caveat: Your project's Deployment Target needs to be set to iOS 11.0.
(short answer to the question update: there is UIColor(named: "MyColor") in Xcode 9.0)
Answering the original question:
you create your color set
you find your color among your snippets and you drag-n-drop it
it will translate to a color literal when looking at the source code:
#colorLiteral(red: 0, green: 0.6378085017, blue: 0.8846047521, alpha: 1)
You notice how the values of red, green and blue are different? It's because I defined them using Color Space Display P3, but the colorLiteral is using Color Space sRGB.
In Xcode 11 press command + shift + L , it will open a snippet , select last one like i showed in image drag and drop .
Short Version
Add a colour set to an asset catalog, name it and set your colour in the attributes inspector, then call it in your code with UIColor(named: "MyColor").
Full Instructions
In the asset catalog viewer, click the plus button at the bottom right of the main panel and choose New Color Set
Click on the white square, and select the Attributes Inspector (right-most icon in the right pane)
From there you can name and choose your colour.
To use it in your code, call it with UIColor(named: "MyColor"). This returns an optional, so you'll need to unwrap it in most cases (this is probably one of the few cases where a force unwrap is acceptable, given you know the colour exists in your asset catalog).
You need to use UIColor(named: "appBlue").
And you can create a function in UIColor extension for simple access.
enum AssetsColor {
case yellow
case black
case blue
case gray
case green
case lightGray
case separatorColor
case red
}
extension UIColor {
static func appColor(_ name: AssetsColor) -> UIColor? {
switch name {
case .yellow:
return UIColor(named: "appYellow")
case .black:
return UIColor(named: "appBlack")
case .blue:
return UIColor(named: "appBlue")
case .gray:
return UIColor(named: "appGray")
case .lightGray:
return UIColor(named: "appLightGray")
case .red:
return UIColor(named: "appRed")
case .separatorColor:
return UIColor(named: "appSeparatorColor")
case .green:
return UIColor(named: "appGreen")
}
}
}
You can use it like this:
userNameTextField.textColor = UIColor.appColor(.gray)
You can use this way for simple accessing (swift 4 & swift 5)
enum AssetsColor: String {
case backgroundGray
case blue
case colorAccent
case colorPrimary
case darkBlue
case yellow
}
extension UIColor {
static func appColor(_ name: AssetsColor) -> UIColor? {
return UIColor(named: name.rawValue)
}
}
Using:
userNameTextField.textColor = UIColor.appColor(.blue)
// iOS
let color = UIColor(named: "SillyBlue")
// macOS
let color = NSColor(named: "SillyBlue")
For your question if you can access color assets like the image using literal, as of Xcode 10.2 you can type in colorliteral, then you can pick the color you want to use that is under your asset manager.
In case you experience a delay with colors loading in a Swift Package when using UIColor(named:):
The answers above are totally valid for a regular project but if you are using assets in a swift package, you can see a delay when loading the colors when you use UIColor(named: "example_name"). If you use UIColor(named: "background", in: Bundle.module, compatibleWith: .current) overload that is targeting the module, the colors load immediately without any delay.
Note: I experienced this on Xcode 12.1.
for swiftUI create a class and name it : Color+extansion and extend Color :
import SwiftUI
extension Color {
static let background = Color("BackgroundColor")
static let whiteColor = Color("WhiteColor")
static let blackColor = Color("BackgroundColor")
static let primery = Color("PrimeryColor")
static let secondaryColor = Color("SecondaryColor")
}
Or, with the SwiftUI Color structure, you can simply call the initializer with the asset name:
Color("background")
you can create extension with func for unwrapping colors from assets and use it with every color in your app
extension UIColor {
static var someColor: UIColor {
return UIColor.color(name: "SomeColor")
}
private static func color(name: String) -> UIColor {
guard let color = UIColor(named: name) else {
return .black
}
return color
}
}
usage example:
UIColor.someColor
or
someLabel.textColor = .someColor