6

I have been attempting to set the statusbar in my SwiftUI app to light text as it has a dark background.

I found this solution on several sites but cannot get it to work.

HostingController.swift

import Foundation
import UIKit
import SwiftUI

class HostingController : UIHostingController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
    }
}

This returns an error on the class declaration line Reference to generic type 'UIHostingController' requires arguments in <...> with a suggested fix of Insert '<<#Content: View#>>'. Applying said fix results in the error Use of undeclared type '<#Content: View#>'

You are then meant to change the window.rootViewController in the SceneDelegate.swift file.

SceneDelegate.swift

...

// Create the SwiftUI view that provides the window contents.
        let contentView = Login()

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = HostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }

...

This throws an error on the window.rootViewController line Argument passed to call that takes no arguments

Anyone got any ideas? Seems like a lot of bother just to set the status bar colour which I imagine would be a fairly common requirement.

4 Answers 4

6

Another way to extend UIHostingController is to keep the generic Content type, then you don't have to pass the session store:

class HostingController<Content>: UIHostingController<Content> where Content: View {
    @objc override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

then in your scene delegate:

window.rootViewController = HostingController(rootView: contentView)
Sign up to request clarification or add additional context in comments.

1 Comment

This works awesome. My issue was the some: View and onTapGesture wouldn't work unless the generics were correct as above. I also didn't need the @objc. Which let me also do: ``` if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = HostingController( rootView: homeView.onTapGesture { window.endEditing(true) } ) self.window = window window.makeKeyAndVisible() } ```
6

Your HostingController needs a concrete type of the rootView:

class HostingViewController<Content: View>: UIHostingController<Content> {

    @objc override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

Then use it in func scene(_ scene: UIScene, willConnectTo... as the rootViewController:

let contentView = ContentView()
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        
        window.rootViewController = HostingViewController(rootView: AnyView(contentView.environmentObject(SessionStore())))
        self.window = window
        window.makeKeyAndVisible()
    }

You won't see any difference in canvas unfortunately, but try it on a simulator.

6 Comments

Thanks. This works. However I have to remove my environmentObject to make it work HostingController(rootView: contentView.environmentObject(SessionStore()) otherwise it requires fixing to HostingController(rootView: contentView.environmentObject(SessionStore()) as! ContentView) which then throws a SIGABRT error when run.
Try declaring like this: HostingViewController: UIHostingController<AnyView> and then erasing your rootview to AnyView HostingController(rootView: AnyView(contentView.environmentObject(SessionStore())))
window.rootViewController = AnyView HostingController(rootView: AnyView(contentView.environmentObject(SessionStore()))) throws the error Cannot assign value of type 'AnyView.Type' to type 'UIViewController?'
It's not quite what I had in mind. Please see my edited answer.
Works like a charm window.rootViewController = HostingController(rootView: AnyView(contentView.environmentObject(SessionStore())))
|
3

In iOS 14 you just need to change/add 2 keys in Info.plist:

enter image description here

3 Comments

This is the correct answer as of iOS 14. There is no longer any requirement to code this in. Change the settings as indicated above in the Info.plist file.
Here's a video showing how to update the Info.plist: youtu.be/w-I5I8POMSI
That works nice and clean! Please note, that this will change the status bar for the whole app. If you need to change it on a view basis you may want to check out this: github.com/xavierdonnellon/swiftui-statusbarstyle
0

I'm a bit late, but you can use generics better:

class HostingController<ContentView: View>: UIHostingController<ContentView> {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .darkContent
    }
}

This allows you to pass any view to the HostingController even with .environmentObject() view modifier.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.