Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Darkmode and multiwindows / scenes

i'm trying to implement ios13 darkmode within multi scene application.

Unfortunately when i dismiss a scene dragging it over the screen edge the method traitCollectionDidChange is called several times with always different values, causing my UI to flicker between dark and light mode.

What's wrong?

Here is my implementation

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

    print("THEME instance: \(self)")  

    let currentTraitCollection = self.traitCollection  
    var hasUserInterfaceStyleChanged = false  
    hasUserInterfaceStyleChanged = previousTraitCollection.hasDifferentColorAppearanceCompared(to: currentTraitCollection)  

    print("THEME hasUserInterfaceStyleChanged = \(hasUserInterfaceStyleChanged ? "YES" : "NO")")  

    if hasUserInterfaceStyleChanged {  
        let userInterfaceStyle = currentTraitCollection.userInterfaceStyle // Either .unspecified, .light, or .dark  

        switch userInterfaceStyle {  
            case .unspecified:  
                print("THEME UIUserInterfaceStyleUnspecified")  
            case .light:  
                print("THEME UIUserInterfaceStyleLight")  
            case .dark:  
                print("THEME UIUserInterfaceStyleDark")  
            }  
    } else {  
        print("THEME NOT CHANGED")  
    }  

}  

Here is the logged statements in console

When new scene comes in...

THEME instance: <MainControllerViewController: 0x117e55910>  
THEME hasUserInterfaceStyleChanged = YES  
THEME UIUserInterfaceStyleLight  

When added scene goes away...

THEME instance: <MainControllerViewController: 0x117e55910>  
THEME hasUserInterfaceStyleChanged = YES  
THEME UIUserInterfaceStyleDark  
THEME instance: <MainControllerViewController: 0x117e55910>  
THEME hasUserInterfaceStyleChanged = YES  
THEME UIUserInterfaceStyleLight  
THEME instance: <MainControllerViewController: 0x117e55910>  
THEME hasUserInterfaceStyleChanged = NO  
THEME NOT CHANGED  
THEME instance: <MainControllerViewController: 0x117e55910>  
THEME hasUserInterfaceStyleChanged = YES  
THEME UIUserInterfaceStyleDark  
THEME instance: <MainControllerViewController: 0x117e55910>  
THEME hasUserInterfaceStyleChanged = YES  
THEME UIUserInterfaceStyleLight  

in meantime i have no changed to dark mode (always light)...so i expect just THEME NOT CHANGED.

like image 724
Fabiosoft Avatar asked Dec 14 '25 05:12

Fabiosoft


1 Answers

I was struggling with the same issue and the solution I worked out is in the SceneDelegate.

A UIScene has multiple states:

.foregroundActive
.foregroundInactive
.background
.unattached

When you are resizing windows in slide over, or in this case, removing one from slide over, traitCollectionDidChange gets called for each of them. This means that you are updating the userInterfaceStyle for scenes in the .background, .foregroundInactive, and .unattached states. This is what's causing the flickering.

The solution is to not use traitCollectionDidChange, but to use a delegate method in SceneDelegate called windowScene(_:didUpdate:interfaceOrientation:traitCollection:).

Per Apple's docs this method:

Notifies you when the size, orientation, or traits of a scene change.

The added benefit of this is that we can check the .activationState of the scene before updating the userInterfaceStyle.

    func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation, traitCollection previousTraitCollection: UITraitCollection) {

          let currentTraitCollection = windowScene.traitCollection

          if windowScene.activationState == .foregroundActive {
             if currentTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle {
                 if currentTraitCollection.userInterfaceStyle == .light {
                     //update to light theme
                 } else {
                     //update to dark theme
                 }
             }
         }
     }
like image 76
Shawn Hickman Avatar answered Dec 16 '25 23:12

Shawn Hickman