Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle status bar with custom overlay UIWindow #908

Open
onmyway133 opened this issue Nov 22, 2022 · 0 comments
Open

How to handle status bar with custom overlay UIWindow #908

onmyway133 opened this issue Nov 22, 2022 · 0 comments

Comments

@onmyway133
Copy link
Owner

onmyway133 commented Nov 22, 2022

When we add another UIWindow, then its rootViewController will decide the style of the status bar, not the rootViewController of the keyWindow anymore

childForStatusBarStyle

The usual way to fix this is to defer the decision to the correct rootViewController, like in our HUDViewController

class HUDViewController: UIViewController {
    override var childForStatusBarStyle: UIViewController? {
        let windows = view.window?.windowScene?.windows ?? []
        for window in windows where window != self.view.window {
            return window.rootViewController?.childForStatusBarStyle
        }
        
        return nil
    }
}

This works, but in case we present some view controllers, the status bar now lays on a dark content. And we don't know when to call setNeedsStatusBarAppearanceUpdate for childForStatusBarStyle to kick in again

Overriding rootViewController

A workaround is to override rootViewController to return the keyWindow rootViewController instead

final class HUDWindow: UIWindow {
    override public var rootViewController: UIViewController? {
        get {
            for window in windowScene?.windows where self != window {
                if let rootViewController = window.rootViewController {
                    return rootViewController
                }
            }
            return super.rootViewController
        }
        set {
            super.rootViewController = newValue
        }
    }
}

This comes with another problem: our HUDWindow now propagates the safeAreaInsets to the keyWindow rootViewController instead of its own rootViewController, resulting in wrong area insets for the HUD content.

One way to fix this is to listen to safeAreaInsetsDidChange. I found out that by altering additionalSafeAreaInsets, the view controller somehow invalidates its safeAreaInsets

class HUDWindow: UIWindow {
    public override func safeAreaInsetsDidChange() {
        super.rootViewController?.additionalSafeAreaInsets = safeAreaInsets
        DispatchQueue.main.async {
            super.rootViewController?.additionalSafeAreaInsets = .zero
        }
    }
}

Another way is to reach to safeAreaInsets from the window instead. For example from HUDViewController

SwiftUIView()
   .ignoresSafeArea(.all, edges: .all)
   .padding(view.window?.safeAreaInsets)

modalPresentationCapturesStatusBarAppearance

modalPresentationCapturesStatusBarAppearance

Specifies whether a view controller, presented non-fullscreen, takes over control of status bar appearance from the presenting view controller.

We can set modalPresentationCapturesStatusBarAppearance to false to prevent the hud view controller from taking over the status bar style decision

hudViewController.modalPresentationCapturesStatusBarAppearance = false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant