Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I easily support light and dark mode with a custom color used in my app?

Tags:

Let's say I have a custom color in my app:

extension UIColor {     static var myControlBackground: UIColor {         return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)     } } 

I use this in a custom control (and other places) as the control's background:

class MyControl: UIControl {     override init(frame: CGRect) {         super.init(frame: frame)          setup()     }      required init?(coder: NSCoder) {         super.init(coder: coder)          setup()     }      private func setup() {         backgroundColor = .myControlBackground     }      // Lots of code irrelevant to the question } 

With iOS 13, I wish to have my custom control support both light and dark mode.

One solution is to override traitCollectionDidChange and see if the color has changed and then update my background as needed. I also need to provide both a light and dark color.

So I update my custom colors:

extension UIColor {     static var myControlBackgroundLight: UIColor {         return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)     }     static var myControlBackgroundDark: UIColor {         return UIColor(red: 0.4, green: 0.3, blue: 0.2, alpha: 1)     } } 

And I update my control code:

extension MyControl {     override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {         super.traitCollectionDidChange(previousTraitCollection)          if #available(iOS 13.0, *) {             if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {                 backgroundColor = traitCollection.userInterfaceStyle == .dark ?                    .myControlBackgroundDark : .myControlBackgroundLight             }         }     } } 

This seems to work but it's clunky and anywhere else I happen to use myControlBackground needs to have the same code added.

Is there a better solution to having my custom color and control support both light and dark mode?

like image 529
rmaddy Avatar asked Jun 07 '19 03:06

rmaddy


People also ask

How do I make iOS app compatible with dark mode?

Once you start building your app using Xcode 11 you'll notice that the darker appearance is enabled by default. If you don't have the time to add support for Dark mode you can simply disable it by adding the UIUserInterfaceStyle to your Info. plist and set it to Light .

What is the color code for dark mode?

Dark gray surfaces can express a wider range of color, elevation, and depth because it's easier to see shadows on gray (instead of a true black). Material design recommends #121212 as dark theme surface color. The recommended dark theme surface color is #121212.


1 Answers

As it turns out, this is really easy with the new UIColor init(dynamicProvider:) initializer.

Update the custom color to:

extension UIColor {     static var myControlBackground: UIColor {         if #available(iOS 13.0, *) {             return UIColor { (traits) -> UIColor in                 // Return one of two colors depending on light or dark mode                 return traits.userInterfaceStyle == .dark ?                     UIColor(red: 0.5, green: 0.4, blue: 0.3, alpha: 1) :                     UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)             }         } else {             // Same old color used for iOS 12 and earlier             return UIColor(red: 0.3, green: 0.4, blue: 0.5, alpha: 1)         }     } } 

That's it. No need to define two separate statics. The control class doesn't need any changes from the original code. No need to override traitCollectionDidChange or anything else.

The nice thing about this is that you can see the color change in the app switcher immediately after changing the mode in the Settings app. And of course the color is up-to-date automatically when you go back to the app.

On a related note when supporting light and dark mode - Use as many of the provided colors from UIColor as possible. See the available dynamic colors from UI Elements and Standard Colors. And when you need your own app-specific colors to support both light and dark mode, use the code in this answer as an example.


In Objective-C, you can define your own dynamic colors with:

UIColor+MyApp.h:

@interface UIColor (MyApp)  @property (class, nonatomic, readonly) UIColor *myControlBackgroundColor;  @end 

UIColor+MyApp.m:

+ (UIColor *)myControlBackgroundColor {     if (@available(iOS 13.0, *)) {         return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traits) {             return traits.userInterfaceStyle == UIUserInterfaceStyleDark ?                 [self colorWithRed:0.5 green:0.4 blue:0.2 alpha:1.0] :                 [self colorWithRed:0.3 green:0.4 blue:0.5 alpha:1.0];         }];     } else {         return [self colorWithRed:0.3 green:0.4 blue:0.5 alpha:1.0];     } } 
like image 73
rmaddy Avatar answered Oct 20 '22 05:10

rmaddy