Navigation toolbar item appearing after a millisecond when I navigate from UIKit to SwiftUI view

222 Views Asked by At

This is what my simplified SwiftUI view looks like:

struct NotificationsView: View {
    
    var body: some View {
        if #available(iOS 16.0, *) {
            notificationsView.toolbarRole(.editor)
        } else {
            notificationsView
        }
    }
    
    private var notificationsView: some View {
        NavigationView {
            ScrollView {
                …
            }
        }.toolbar {
            ToolbarItem(placement: .principal) {
                Text("Notifications")
                    .font(.headline)
                    .foregroundColor(.gray)
            }
        }
    }
}

The view before this one is a UIKit view, so when I navigate to the NotificationsView, it takes a millisecond for the title to appear, and for the back button text to go away (which is what I want - just the arrow). See the gif:

Title appearing after a millie second

This is what I do to display the NotificationsView:

let view = notificationsViewProvider.create(notifications: notifications)
let vc = UIHostingController(rootView: view)
rootNavigationController.setNavigationBarHidden(false, animated: false)
rootNavigationController.show(vc, sender: self)

It's similar even with animated: true, it doesn't change much the output.

I have tried this on a demo project with two views and the same code works fine, except there both views are SwiftUI.

Any ideas on how it could be fixed?

1

There are 1 best solutions below

0
On

The best solution I can think of is not mixing the SwiftUI and UIKit navigation bars.

As your initial view is an UIKit view controller I would prefer using UIKit navigation bar through the whole navigation. Something like this:

final class UIKitViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Configure the back button here
        navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    }
    
    func onPush() {
        let notificationsView = SwiftUINotificationsViewController(rootView: NotificationsView())
        navigationController?.pushViewController(notificationsView, animated: true)
    }
}

final class SwiftUINotificationsViewController: UIHostingController<NotificationsView> {
    override func viewDidLoad() {
        super.viewDidLoad()

        // Configure the title here
        let titleLabel = UILabel()
        titleLabel.attributedText = .init(string: "Notifications", attributes: [
            .foregroundColor: UIColor.blue,
            .font: UIFont.systemFont(ofSize: 17.0, weight: UIFont.Weight.light)
        ])

        self.navigationItem.titleView = titleLabel
    }
}

struct NotificationsView: View {
    var body: some View {
        if #available(iOS 16.0, *) {
            notificationsView.toolbarRole(.editor)
        } else {
            notificationsView
        }
    }
    
    private var notificationsView: some View {
        ScrollView {
            // Setup your view
            // Don't use toolbar or any navigation item configuration here
        }
    }
}