kettlepot
kettlepot

Reputation: 11011

iPad: White text on one side of the status bar, black text on the other

The Home app on iPadOS 14 displays black text on the left side of the status bar, and white text on the right side. How is this achieved? Can it be done via public APIs?

example image from Home app

Upvotes: 2

Views: 270

Answers (2)

hayesk
hayesk

Reputation: 594

This can be done only if the root view controller is a UISplitViewController. I've set one up with the new splitview column styles in iOS 14, but the older way should work too.

Then you need to get the navigationController from each viewController and set the barStyle on its navigationBar to .default or .black

After placing your splitViewController as the root viewController of your UIWindow in your scene function, set the style as below:

    var embeddedSplitViewController: UISplitViewController?

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

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

            self.embeddedSplitViewController?.viewController(for: .primary)?.navigationController?.navigationBar.barStyle = .black
            self.embeddedSplitViewController?.viewController(for: .secondary)?.navigationController?.navigationBar.barStyle = .default
        }
    }

    func makeSplitViewController() {
        let splitViewController = UISplitViewController(style: .doubleColumn)

        // I have SwiftUI Views here but they could be any UIViewController
        let primaryViewController = UIHostingController(rootView: SidebarView())

        splitViewController.setViewController(primaryViewController, for: .primary)
        splitViewController.setViewController(UIHostingController(rootView: DetailView()), for: .secondary)

        let compactViewController = UIHostingController(rootView: SidebarView())
        splitViewController.setViewController(compactViewController, for: .compact)

        splitViewController.preferredPrimaryColumnWidth = 320
        self.embeddedSplitViewController = splitViewController
    }

This worked for me, and the statusBar reflected the barStyle and updated accordingly when showing and hiding the primary viewController.

Upvotes: 0

mushcraft
mushcraft

Reputation: 2244

Can it be done via public APIs?

Yes, it's all defined in UIBarStyle. Since each uiviewcontroller added to a splitview is embedded into its own UINavigationController, you can set the barstyle for each uiviewscontroller.navigationController!.navigationBar.barStyle

For white text, choose .black, and .default is black text. myHomeViewController.navigationController!.navigationBar.barStyle = .black

you could also create your own viewcontrollers and define they're preferredstatusbarstyle to be .lightContent or .darkContent by overriding the childForStatusBarStyle as per the docs.

You can override the preferred status bar style for a view controller by implementing the childForStatusBarStyle method.

As per Apples wwdc20 Build for iPad. Home was rebuilt using the new features of UISplitViewController.

Minus the button and fancy background. Home split view is a UISplitViewController initialized with the doubleColumn style. UISplitViewController(style: .doubleColumn)

Example of creating a split view in code only in SceneDelegate.swift of a new project:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
            guard let windowScene = (scene as? UIWindowScene) else { return }
            //UISplitViewControllerDelegate
            splitViewController.delegate = self
            //set which view is what
            splitViewController.setViewController(sidebarViewController, for: .primary)
            splitViewController.setViewController(myHomeViewController, for: .secondary)
            
            //setup of sidebar and detail controllers
            sidebarViewController.navigationController?.navigationBar.prefersLargeTitles = true
            myHomeViewController.navigationController?.navigationBar.prefersLargeTitles = true
            
            sidebarViewController.title = "Home"
            myHomeViewController.title = "Home"
            
            //appear side by side when a column is shown, use tile style.
            splitViewController.preferredSplitBehavior = .tile

            //'color' myHomeViewController statusbar to white, by setting barStyle = .black
            myHomeViewController.navigationController!.navigationBar.barStyle = .black
            //start styling your navigation controllers, As i've set preferesLargeTitles, style the navBars largeTitleTextAttributes
            myHomeViewController.navigationController!.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
            //style viewcontroller
            myHomeViewController.view.backgroundColor = .blue
            // always have primary and secondary sidebyside
            //splitViewController.preferredDisplayMode = .oneBesideSecondary
            splitViewController.show(.primary)
            splitViewController.show(.secondary)
            
            window = UIWindow(windowScene: windowScene)
            window?.rootViewController = splitViewController
            window?.makeKeyAndVisible()
    }

Other helpful resources I found:

TLDW wwdc20 notes

UISplitViewController apple docs

Upvotes: 1

Related Questions