3

I've discovered a weird behavior on iOS 11 when I push UIViewController and change the UINavigationBar color to transparent. Important thing is that I'm using largeTitles.

  1. I want to change red color of the navigation bar to transparent and this works fine.

  2. However, if I tap on backButton, disable transparent style and red color style again something bad happened. NavigationBar on the ViewController is not red but still transparent.

  3. As @Menoor Ranpura suggest I add another line which sets also a backgroundColor of view in UIViewController - and this is fine workaround when you set the same color like on UINavigationBar. However, it's not the solution for the problem because the large part of the navigation bar is still transparent. You can see it when you set the different color for a background. For example, I set the yellow. You can see the example here:

enter image description here

Question

How to properly change the navigation bar color from transparent to red again, when the prefersLargeTitles is set to true?

Code

class ExampleTableTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuseID")
        navigationController?.navigationBar.redNavigationBar()
        title = "Red NavBar"
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        view.backgroundColor = .yellow
        navigationController?.navigationBar.redNavigationBar()
    }
}

 //Transparent Navigation bar controller
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Transparent NavBar"
        view.backgroundColor = .blue
        self.navigationController?.navigationBar.prefersLargeTitles = true
    }

    override func viewWillAppear(_ animated: Bool) {
        self.navigationController?.navigationBar.transparentNavigationBar()
    }

}
extension UINavigationBar {
    func redNavigationBar() {
        setBackgroundImage(nil, for: .default)
        shadowImage = nil


        prefersLargeTitles = true
        tintColor = .white
        largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
        titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
        barTintColor = .red
    }

    func transparentNavigationBar() {
        setBackgroundImage(UIImage(), for: .default)
        shadowImage = UIImage()
    }
}

Some tips that I've already tested:

  • Everything works fine when prefersLargeTitles is set to false
  • Everything works fine when prefersLargeTitles is set to true, but navigationBar changes are between non transparent colors. For example, if changing between green <-> yellow
  • I don't want to set backgroundColor on view. It's not an solution but kind of a workaround for this.

Here you can see a screen from XCode:

enter image description here

Interesting fact is that, there is something called: _UINavigationBarLargeTitleView which is transparent. How to access it?

Related problems:

You can find example project here: https://github.com/kamwysoc/LargeTitlesNavigationBarTransition


UPDATE referring to @Menoor Ranpura answer

Code that @Menoor Ranpura suggest is a kind of a workaround. It's not a solution to set the same backgroundColor on UIViewController view like UINavigationBar has. However, I go a bit further and I change the color for a different than UINavigationBar controller has. And as you can see on above gif, when the largeTitle appears, the navigation bar becomes yellow - which means that is transparent - because we're able to see the yellow background of view.

kamwysoc
  • 6,709
  • 2
  • 34
  • 48

2 Answers2

1

call greenNavigationBar() in viewWillAppear

override func viewWillAppear(_ animated: Bool)
{
    view.backgroundColor = .red // this is kind of a workaround, However if you set color which will be different that `UINavigationBar` color you see that `largeTitle` is transparent because it shows a `backgroundColor` of a ViewController view.
    navigationController?.navigationBar.greenNavigationBar()
    title = "Green Title"
    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(showTransparentViewController))
}
kamwysoc
  • 6,709
  • 2
  • 34
  • 48
0

Here's how you access _UINavigationBarLargeTitleView. I think you should submit a radar if you haven't already because setting the background colour this private ivar is only a hack and the issue at large still exists.

Swift 3/4:

if let navigationBar = navigationController?.navigationBar,
    let titleView = navigationBar.subviews.first(where: {type(of: $0) == NSClassFromString("_UINavigationBarLargeTitleView")}) {

}

Objective-C:

__block UIView *titleView;

[navigationController.navigationBar.subviews enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger index, BOOL *stop) {
    Class _UINavigationBarLargeTitleView = NSClassFromString(@"_UINavigationBarLargeTitleView");
    if ([subview isKindOfClass:_UINavigationBarLargeTitleView]) {
        titleView = subview;
        *stop = YES;
    }
}];
Mark Bourke
  • 9,806
  • 7
  • 26
  • 30