Skip to content

Instantly share code, notes, and snippets.

@Hiroki-Kawakami
Last active May 7, 2024 18:38
Show Gist options
  • Save Hiroki-Kawakami/231115bd3c2f739781f53ecea39e2c1f to your computer and use it in GitHub Desktop.
Save Hiroki-Kawakami/231115bd3c2f739781f53ecea39e2c1f to your computer and use it in GitHub Desktop.
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

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.

@byslmahmud
Copy link

Its works for me(life saver). Thank you very much.

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