Swift extension and enum for color schemes
Don't use an enum then. If you don't want to enumerate on the values in a switch statement, there is no need for an enum
. Use a struct
with constant attributes.
struct Color {
static let border = UIColor(red:0.92, green:0.93, blue:0.94, alpha:1.00)
static let waterMelon = UIColor(red:0.97, green:0.38, blue:0.45, alpha:1.00)
// and so on ....
}
If you want to extend UIColor to have access to all the other colors of UIColor as well, you can extend UIColor like this:
extension UIColor {
static var border: UIColor {
return UIColor(red:0.92, green:0.93, blue:0.94, alpha:1.00)
}
static var waterMelon: UIColor {
return UIColor(red:0.97, green:0.38, blue:0.45, alpha:1.00)
}
}
How can I make a Swift enum with UIColor value?
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.
Declaring an enum to change color used in app for different type of users
I believe what you want is not possible. Enum may not be a class, only a generic type, a structure.
But it is usually not what you want as when you will have many of these values you will have a mess anyway. For instance at some point you will have a button background color, border color and text color. Then waht do you expect your result to be like:
button.backgroundColor = UIButton.backgroundColor
button.layer.borderColor = UIButton.borderColor.cgColor
button.label.textColor = UIButton.textColor
And now having 3 enums for a single component... It is a solution but I think it is a bad one...
I suggest you rather create a static class and have it like so:
class UserApperance {
static var userType: UserType = .admin
static var navigationTintColor: UIColor {
switch userType {
case .admin: ...
case .user: ...
}
}
}
So all you will do in the code is again
tabBarController.tabBar.barTintColor = UserApperance.navigationTintColor
And when you want to group them you can use nesting:
class UserApperance {
static var userType: UserType = .admin
class NavigationBar {
static var tintColor: UIColor {
switch UserApperance.userType {
case .admin: ...
case .user: ...
}
}
}
}
Where the result is now nicer:
tabBarController.tabBar.barTintColor = UserApperance.NavigationBar.tintColor
In my opinion this is the nicest way and with really hard situations like white-label applications you can really play around with nesting and do it per screen and even have code like:
let appearance = UserAppearance.thisScreenName
titleLabel.textColor = appearance.title.textColor
titleLabel.font = appearance.title.font
Bot to mention you can generalize some things and even have usage as
UserAppearance.thisScreenName.title.configure(label: titleLabel)
Which may set all the property of your UI element...
But if you really, really badly want to have this you can still use something like strings as colors or pretty much any primitive...
You can create extensions like
extension UIView {
var backgroundColorString: String? {
set {
self.backgroundColor = UIColor(hexString: newValue)
}
get {
return self.backgroundColor.toHexString()
}
}
}
Then you obviously use this property to set the color directly from enumeration. But I discourage you to do this.
SwiftUI color extension for creating theme
There are some code mistakes.
- You have created a function with the name
colorColor
but your are called a color - Used wrong
traitCollection
Here is the fixed code.
enum Colors {
enum Content {
static var contentStrongestColor: Color {
return setColor(
dark: Color(red: 0.21568627655506134, green: 0.2549019753932953, blue: 0.3176470696926117),
light: Color(red: 0.8784313797950745, green: 0.8784313797950745, blue: 0.8784313797950745)
)
}
}
enum Background {
static var contentDefaultColor: Color {
return setColor(
dark: Color(red: 0.06666667014360428, green: 0.09019608050584793, blue: 0.15294118225574493),
light: Color(red: 1, green: 1, blue: 1)
)
}
}
}
extension Colors {
static func setColor(dark: Color, light: Color) -> Color {
switch UIScreen.main.traitCollection.userInterfaceStyle {
case .dark: return dark
case .light: return light
default: return light
}
}
}
How to implement a color scheme switch with the system value option?
Thanks to @diogo for his solution. I have adapted it for ios 15 into a custom view which could be used in a settings page:
struct DisplayModeSetting: View {
enum DisplayMode: Int {
case system, dark, light
var colorScheme: ColorScheme? {
switch self {
case .system: return nil
case .dark: return ColorScheme.dark
case .light: return ColorScheme.light
}
}
func setAppDisplayMode() {
var userInterfaceStyle: UIUserInterfaceStyle
switch self {
case .system: userInterfaceStyle = UITraitCollection.current.userInterfaceStyle
case .dark: userInterfaceStyle = .dark
case .light: userInterfaceStyle = .light
}
let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
scene?.keyWindow?.overrideUserInterfaceStyle = userInterfaceStyle
}
}
@AppStorage("displayMode") var displayMode = DisplayMode.system
var body: some View {
HStack {
Text("Display mode:")
Picker("Is Dark?", selection: $displayMode) {
Text("System").tag(DisplayMode.system)
Text("Dark").tag(DisplayMode.dark)
Text("Light").tag(DisplayMode.light)
}
.pickerStyle(SegmentedPickerStyle())
.onChange(of: displayMode) { newValue in
print(displayMode)
displayMode.setAppDisplayMode()
}
}
}
}
Swift constants: Struct or Enum
Both structs and enumerations work. As an example, both
struct PhysicalConstants {
static let speedOfLight = 299_792_458
// ...
}
and
enum PhysicalConstants {
static let speedOfLight = 299_792_458
// ...
}
work and define a static property PhysicalConstants.speedOfLight
.
Re: A struct will be copied every time i use it or not?
Both struct
and enum
are value types so that would apply to enumerations as well. But that is irrelevant here
because you don't have to create a value at all:
Static properties (also called type properties) are properties of the type itself, not of an instance of that type.
Re: What advantages has the choice of a struct or enum?
As mentioned in the linked-to article:
The advantage of using a case-less enumeration is that it can't accidentally be instantiated and works as a pure namespace.
So for a structure,
let foo = PhysicalConstants()
creates a (useless) value of type PhysicalConstants
, but
for a case-less enumeration it fails to compile:
let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers
What is the best way to introduce a custom UIColor to a Swift project?
Answer: Extension, in my professional opinion.
Think about it; you are, in philosophy, 'extending' the range of colors offered by UIColor
. Provided that your color name is distinct and the new function follows Apple's method naming protocol (i.e. <color name>Color
), extending UIColor
seems neater. One or two new colors (in my opinion) don't warrant an entire dedicated struct
.
Bonus answer:
Where would a struct
(or enum
!) be a good fit?
- If your app forces replacements for the standard colors (i.e. custom
'primary' colors) - If your app is specifically designed to be themed / customized, it might be good have an
enum
, to serve as a concrete list for available options. - If you can't think of standard names for the colors (
sharkBlueColor
, anyone?). - If your app is specifically for drawing/painting (in which case a 'palette' construct might be good idea).
... the list goes on. You must learn to discern and decide for yourself as you mature as a Swift developer!
Swift update UIColor when change color
Say you have the following struct to keep track of user preferences keys:
struct PreferenceKeys {
static let themeStyle = "theme_style"
}
And the following enum (with raw type) to describe your theme style:
enum ThemeStyle: Int {
case themeA = 0
case themeB
case themeC
case themeD
}
First I'd create a custom service to manage your theme. Let's call it ThemeService. This will allow you to store and retrieve the active theme style the user picked. It could be as simple as this:
protocol ThemeServiceInterface {
func setThemeStyle(_ themeStyle: ThemeStyle)
func getThemeStyle() -> ThemeStyle
}
final class ThemeService: ThemeServiceInterface {
static let shared = ThemeService()
let userDefaults: UserDefaults
private init() {
self.userDefaults = UserDefaults.standard
}
func setThemeStyle(_ themeStyle: ThemeStyle) {
userDefaults.set(themeStyle.rawValue, forKey: PreferenceKeys.themeStyle)
}
func getThemeStyle() -> ThemeStyle {
let rawValue = userDefaults.integer(forKey: PreferenceKeys.themeStyle)
if let themeStyle = ThemeStyle(rawValue: rawValue) {
return themeStyle
}
return .themeA
}
}
So when you try to access a specific color, simply ask your Theme Service what's the active theme style, and set your color accordingly.
extension UIColor {
static var primaryColor: UIColor {
switch ThemeService.shared.getThemeStyle() {
case .themeA: return .systemBlue
case .themeB: return .systemRed
case .themeC: return .systemGreen
case .themeD: return .systemIndigo
}
}
static var secondaryColor: UIColor {
.systemPink
}
// ...
}
Now when your user wants to set a new theme style, you would just call the following method:
ThemeService.shared.setThemeStyle(.themeC)
This is great, and all your newly created views will reflect the new theme style.
But now comes the part where we need to reset the UI for all the existing views as well. Well, depending on the structure of your project, you would have different options.
For example you could make your ThemeService send a notification via NotificationCenter
to all your screens, asking them to reload their UI (using setNeedsDisplay()
/ setNeedsLayout()
methods for example)
If this sounds like too much work for your project, an other nice and easy way could be to simply reset your UIWindow's rootViewController
with a beautiful animation, which would cause your UI to be resetted and match the active theme style.
Hope it helps!
Related Topics
When Should I Use Anyobject Insted of Uibutton in Swift
Create Navbar Programmatically with Button and Title Swift
Swift - Using Cgcontext to Draw with Finger
Swift Add Line Above to Control
Custom Uitoolbar Too Close to the Home Indicator on iPhone X
How to Detect Which Annotation Was Selected in Mapview
How to Store Array in Nsuserdefault in Swift
Swift: Have Searchbar Search Through Both Sections and Not Combine Them
Changing Font Size in a Label for Only iPhone 4S, Is This Possible
Avmutablevideocomposition Output Video Shrinked
Import Xctest into a Dynamic Framework
Get Center Coordinates from Mapkit and Display in Uilabel
Swiftui - Optional Timer, Reset and Recreate
Setting Custom Http Headers in Alamofire in iOS 7 Not Working
iOS - Uinavigationcontroller, Hide Navigationbar
How to Share Published Model Between Two View Models in Swiftui