Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a transparent navigation bar on push and restore it on pop

I'm trying to create an effect that even though it's close to what I desire but it has some UI glitches which I'll explain.

I have, let's say, my Home navigation controller which I tap a cell that pushes a new view controller.

On that view controller's viewWillAppear(:) I've implemented the following:

self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.backgroundColor = .clear
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.barTintColor = .clear
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)

By doing this, the pushed view controller will have its navigationBar transparent, and still keeps the buttons visible (which is what I desire), but on the push animation, it shows a black bar on the parent controller, because it hides the parent's navigationBaras well.

And then on the pushed view controllers viewWillDisappear(_:) I've implemented the following:

self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.backgroundColor = .white
self.navigationController?.navigationBar.barTintColor = .white

By doing this, I'm trying to reset the parent's navigationBar default properties, but by doing so I see a black bar during the animation, before it completes the animation, which causes a bad UI/UX.

Am I doing something wrong here, or there is any better approach on this?

Thank you.

like image 692
Ivan Cantarino Avatar asked Nov 24 '17 11:11

Ivan Cantarino


People also ask

How do I make my navigation bar transparent?

Creating a transparent navbar is very easy - just don't add a color class . bg-* to the navbar. In this case, the Navbar will take the color of the parent's background color.

What is Scrolledgeappearance?

The appearance settings for the navigation bar when the edge of scrollable content aligns with the edge of the navigation bar. iOS 13.0+ iPadOS 13.0+ Mac Catalyst 13.1+ tvOS 13.0+

What is a navigation controller?

NavController manages app navigation within a NavHost . Apps will generally obtain a controller directly from a host, or by using one of the utility methods on the Navigation class rather than create a controller directly. Navigation flows and destinations are determined by the navigation graph owned by the controller.


1 Answers

So after some digging and some pretty useful hints from @Paulo I have managed to solve this as I wanted to.

This is something that should be way more simple to achieve, and Apple should give developers that simplicity option and not tweaking around some hack to achieve it, but anyway.

I found that one of the secret was that I was abusing the navigationBar.isTranslucent = true / false when navigating through the view controllers.

In order to do this I set the default navigationBar properties in the parentViewController, the one that will push to the view controller with the transparent navigationBar; I've done it as the following:

self.navigationController?.navigationBar.backgroundColor = .white
self.navigationController?.navigationBar.barTintColor = .white
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)

On the pushedViewController viewWillAppear(_:) you need to implement the following:

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

    guard self.navigationController?.topViewController === self else { return }
    self.transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
        self?.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        self?.navigationController?.navigationBar.shadowImage = UIImage()
        self?.navigationController?.navigationBar.backgroundColor = .clear
        self?.navigationController?.navigationBar.barTintColor = .clear
    }, completion: nil)
}

Here I set the desired navigationBar transparency, but as you notice, no need to use the isTranslucent property, I noticed by forcing it the UI would show some flickering and weird layout on the push animation.

Then on the same view controller (pushed) you need to implement the default, desired, navigationBar properties that you've implemented in the parentViewController:

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

    self.transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
        self?.navigationController?.navigationBar.setBackgroundImage(nil, for: UIBarMetrics.default)
        self?.navigationController?.navigationBar.shadowImage = nil
        self?.navigationController?.navigationBar.backgroundColor = .white
        self?.navigationController?.navigationBar.barTintColor = .white
        }, completion: nil)
}

And by doing this everything should work as expected.

Hope it helps someone in the future.

like image 100
Ivan Cantarino Avatar answered Sep 24 '22 15:09

Ivan Cantarino