1
votes

In my app's navigation controller, I want to push a view controller with a clear navigation bar and toolbar. When the first view controller appears again, I want the navigation bar and toolbar to have their default appearances again.

I turned on Slow Animations in the simulator settings so you can see how it looks:

Demo video

The areas above the navigation bar and underneath the home indicator don't look quite right during the transition because there's nothing there, while the actual navigation bar and toolbar fade out.

Also, when popping the controller, the toolbar appears instantly. This especially looks bad when dismissing it interactively with the swipe back gesture.

I might be able to get it to look good using the new UIBarAppearance classes in iOS 13, but I want to continue to support older versions of iOS.

This is the code I have so far. These methods are inside the detail view controller. Also I don't want to really set the background color to white, but get the default blurred appearance, even in dark mode, but am not sure what to set it back to.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    func doThings() {
        navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        navigationController?.navigationBar.shadowImage = UIImage()
        navigationController?.navigationBar.backgroundColor = .clear
        navigationController?.navigationBar.barTintColor = .clear

        navigationController?.toolbar.setBackgroundImage(UIImage(), forToolbarPosition: .bottom, barMetrics: .default)
        navigationController?.toolbar.setShadowImage(UIImage(), forToolbarPosition: .bottom)
        navigationController?.toolbar.backgroundColor = .clear
        navigationController?.toolbar.barTintColor = .clear
    }

    guard self.navigationController?.topViewController === self else { return }
    let animationsWereQueuedSuccessfully = self.transitionCoordinator?.animate(alongsideTransition: { [weak self] context in
        guard self != nil else { return }
        doThings()
    }, completion: nil)

    if animationsWereQueuedSuccessfully != true {
        doThings()
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    func doThings() {
        navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default)
        navigationController?.navigationBar.shadowImage = nil
        navigationController?.navigationBar.backgroundColor = .white
        navigationController?.navigationBar.barTintColor = .white

        navigationController?.toolbar.setBackgroundImage(nil, forToolbarPosition: .bottom, barMetrics: .default)
        navigationController?.toolbar.setShadowImage(nil, forToolbarPosition: .bottom)
        navigationController?.toolbar.backgroundColor = .white
        navigationController?.toolbar.barTintColor = .white
    }

    let animationsWereQueuedSuccessfully = self.transitionCoordinator?.animate(alongsideTransition: { [weak self] context in
        guard self != nil else { return }
            doThings()
    }, completion: nil)

    if animationsWereQueuedSuccessfully != true {
        doThings()
    }
}
1

1 Answers

1
votes

I would suggest doing a custom transition. It sounds like you need more power than a default push. Here is a medium article.

https://medium.com/chili-labs/custom-navigation-transitions-f791ff0a46aa