Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect Light\Dark mode change in iOS 13?

Some of the UI setups not working automatically with the Dark/Light mode change as the UIColor. For example shadow in layer. As I need to remove and drop shadow in dark and light mode, I need somewhere to put updateShadowIfNeeded() function. I know how to detect what is the mode currently:

func dropShadowIfNeeded() {
    switch traitCollection.userInterfaceStyle {
    case .dark: removeShadow()
    case .light: dropShadowIfNotDroppedYet()
    default: assertionFailure("Unknown userInterfaceStyle")
    }
}

Now I put the function inside the layoutSubviews, since it gets called every time appearance change:

override func layoutSubviews() {
    super.layoutSubviews()
    dropShadowIfNeeded()
}

But this function is getting called A LOT. What is the proper function to trigger only if userInterfaceStyle changed?

like image 309
Mojtaba Hosseini Avatar asked Sep 19 '19 18:09

Mojtaba Hosseini


People also ask

How do I know if dark mode is enabled iOS?

Dark mode can be detected by using the userInterfaceStyle property on the current trait collection. When it's set to dark you know that the current appearance is set to dark.

Does iOS 13 support dark mode?

The Box Mobile team is excited to announce the Box iOS app now offers Dark Mode support for an optimal viewing experience in low-light environments. Dark Mode will be supported on devices with iOS 13 and higher. To enable Dark Mode, go to your device system settings (Settings-->Display & Brightness-->Dark Mode button).

How do you know if in dark mode Swift?

We simply have to add a @Enviroment variable and use . colorScheme property to scan the settings on our device and see if dark mode is enabled. Let's take a look at the example below. struct ContentView: View { @Environment(\.


2 Answers

SwiftUI

With a simple environment variable on the \.colorScheme key:

struct ContentView: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text(colorScheme == .dark ? "Its Dark" : "Its. not dark! (Light)")
    }
}

UIKit

As it described in WWDC 2019 - Session 214 around 23:30.

As I expected, this function is getting called a lot including when colors changing. Along side with many other functions for ViewController and presentationController. But there is some especial function designed for that has a similar signature in all View representers.

Take a look at this image from that session:

WWDC 2019 - Session 214

Gray: Calling but not good for my issue, Green: Designed for this

So I should call it and check it inside this function:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    
    if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
        dropShadowIfNeeded()
    }
}

This will guarantee to be called just once per change.

if you are only looking for the initial state of the style, check out this answer here

like image 190
Mojtaba Hosseini Avatar answered Oct 01 '22 20:10

Mojtaba Hosseini


I think this should get called significantly less often, plus the guard makes sure you only react to user interface style changes:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else {
        return
    }
    dropShadowIfNeeded()
}
like image 35
LuLuGaGa Avatar answered Oct 01 '22 19:10

LuLuGaGa