Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
SwiftUI Change Status Bar Color with UIWindow
//
// ContentView.swift
// StatusBarTest
//
// Created by hiroki on 2021/02/11.
//
import SwiftUI
struct ContentView: View {
@StateObject var statusBarConfigurator = StatusBarConfigurator()
var body: some View {
VStack(spacing: 30) {
Text("Status Bar Color Test")
.font(.title)
Button("Black") {
statusBarConfigurator.statusBarStyle = .darkContent
}
Button("White") {
statusBarConfigurator.statusBarStyle = .lightContent
}
}
.prepareStatusBarConfigurator(statusBarConfigurator) // UIWindowの用意
.frame(maxWidth: .infinity, maxHeight: .infinity) // 背景色をステータスバーまで広げるため
.background(Color.gray.ignoresSafeArea()) // ステータスバーの色をわかりやすくするために背景をグレーに
}
}
//
// StatusBarConfigurator.swift
// StatusBarTest
//
// Created by hiroki on 2021/02/11.
//
import UIKit
import SwiftUI
class StatusBarConfigurator: ObservableObject {
private var window: UIWindow?
var statusBarStyle: UIStatusBarStyle = .default {
didSet {
window?.rootViewController?.setNeedsStatusBarAppearanceUpdate()
}
}
fileprivate func prepare(scene: UIWindowScene) {
if window == nil {
let window = UIWindow(windowScene: scene)
let viewController = ViewController()
viewController.configurator = self
window.rootViewController = viewController
window.frame = UIScreen.main.bounds
window.alpha = 0
self.window = window
}
window?.windowLevel = .statusBar
window?.makeKeyAndVisible()
}
fileprivate class ViewController: UIViewController {
weak var configurator: StatusBarConfigurator!
override var preferredStatusBarStyle: UIStatusBarStyle { configurator.statusBarStyle }
}
}
fileprivate struct SceneFinder: UIViewRepresentable {
var getScene: ((UIWindowScene) -> ())?
func makeUIView(context: Context) -> View { View() }
func updateUIView(_ uiView: View, context: Context) { uiView.getScene = getScene }
class View: UIView {
var getScene: ((UIWindowScene) -> ())?
override func didMoveToWindow() {
if let scene = window?.windowScene {
getScene?(scene)
}
}
}
}
extension View {
func prepareStatusBarConfigurator(_ configurator: StatusBarConfigurator) -> some View {
return self.background(SceneFinder { scene in
configurator.prepare(scene: scene)
})
}
}
@ashinthetray
Copy link

ashinthetray commented Mar 24, 2022

Hi there, thanks for this solution.

I noticed that after you set the statusBarStyle to light/dark and then set it back to .default and then iOS will not display the status bar in the correct color when modals (.sheet) are displayed.

Usually iOS inverts the status bar color automatically when modals are displayed, so it appears that behavior gets disabled with this implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment