Skip to content

Instantly share code, notes, and snippets.

@vaskaloidis
Created July 8, 2021 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vaskaloidis/febd21341c6e386ba7b5aac7e47ee8f9 to your computer and use it in GitHub Desktop.
Save vaskaloidis/febd21341c6e386ba7b5aac7e47ee8f9 to your computer and use it in GitHub Desktop.
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .purple
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
} else {
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().barTintColor = .purple
UINavigationBar.appearance().isTranslucent = false
}
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.backgroundColor = // your color
navBarAppearance.shadowImage = nil // line
navBarAppearance.shadowColor = nil // line
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).standardAppearance = navBarAppearance
UINavigationBar.appearance(whenContainedInInstancesOf: [UINavigationController.self]).scrollEdgeAppearance = navBarAppearance
// StatusBarController.swift
// Insert this into your project.
// Created by Xavier Donnellon
//
import SwiftUI
class HostingController<Content: View>: UIHostingController<Content> {
override var preferredStatusBarStyle: UIStatusBarStyle {
return UIApplication.statusBarStyle
}
}
///By wrapping views in a RootView, they will become the app's main / primary view. This will enable setting the statusBarStyle.
struct RootView<Content: View> : View {
var content: Content
init(@ViewBuilder content: () -> (Content)) {
self.content = content()
}
var body:some View {
EmptyView()
.onAppear {
UIApplication.shared.setHostingController(rootView: AnyView(content))
}
}
}
extension View {
///Sets the status bar style color for this view.
func statusBarStyle(_ style: UIStatusBarStyle) -> some View {
UIApplication.statusBarStyleHierarchy.append(style)
//Once this view appears, set the style to the new style. Once it disappears, set it to the previous style.
return self.onAppear {
UIApplication.setStatusBarStyle(style)
}.onDisappear {
guard UIApplication.statusBarStyleHierarchy.count > 1 else { return }
let style = UIApplication.statusBarStyleHierarchy[UIApplication.statusBarStyleHierarchy.count - 1]
UIApplication.statusBarStyleHierarchy.removeLast()
UIApplication.setStatusBarStyle(style)
}
}
}
extension UIApplication {
static var hostingController: HostingController<AnyView>? = nil
static var statusBarStyleHierarchy: [UIStatusBarStyle] = []
static var statusBarStyle: UIStatusBarStyle = .darkContent
///Sets the App to start at rootView
func setHostingController(rootView: AnyView) {
let hostingController = HostingController(rootView: AnyView(rootView))
windows.first?.rootViewController = hostingController
UIApplication.hostingController = hostingController
}
static func setStatusBarStyle(_ style: UIStatusBarStyle) {
statusBarStyle = style
hostingController?.setNeedsStatusBarAppearanceUpdate()
}
}

swiftui-statusbarstyle

https://github.com/xavierdonnellon/swiftui-statusbarstyle Supports changing the Status Bar style with natural SwiftUI syntax.

The status bar changes based on the view.

Installation

Simply add the StatusBarController.swift file into your project.

Usage

With new SwiftUI App Lifecycle

In your @main App file, simply wrap your main view in a RootView.

@main
struct ProjectApp: App {     
    var body: some Scene {
        WindowGroup {
            //wrap main view in RootView
            RootView {
                //Put the view you want your app to present here
                ContentView()
                    //add necessary environment objects here 
            }
        }
    }
}

With AppDelegate / SceneDelegate Lifecycle

In your SceneDelegate.swift, in yourscene(_ scene: UIScene...) function, simply wrap your main view in a RootView.

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        //wrap main view in RootView
        let contentView = RootView {
            //Put the view you want your app to present here
            ContentView()
                //add necessary environment objects here 
        }

        //Rest of function is unchanged 
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
    
    //rest of default SceneDelegate goes unchanged...
}

Example

Use the .statusBarStyle(_ style: UIStatusBarStyle) method on a View.

struct ContentView: View {
    var body: some View {
        TabView {
            //Tab  1 will have a light status bar
            Color.black
                .edgesIgnoringSafeArea(.all)
                .overlay(Text("Light Status Bar").foregroundColor(.white))
                .statusBarStyle(.lightContent) //set status bar style here
                .tabItem { Text("Tab 1") }
            
            //Tab 2 will have a dark status bar
            Color.white
                .edgesIgnoringSafeArea(.all)
                .overlay(Text("Dark Status Bar"))
                .statusBarStyle(.darkContent) //set status bar style here
                .tabItem { Text("Tab 2") }
        }
    }
}
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}}
// Usage
configureNavigationBar(largeTitleColor: .yourColor, backgoundColor: .yourColor, tintColor: .yourColor, title: "YourTitle", preferredLargeTitle: true)
// Set ViewController-based status bar...... to NO in info.plist if you want light Content
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment