Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this new navigation bar behaviour in xcode 11 beta a bug or intended?

I noticed after compiling one of my apps in Xcode 11 beta, that navigation bars have no background when prefersLargeTitles is set. Is this intended behavior?

I noticed this is how the messages app works now when scrolling down and a large title is visible there is no nav bar background.

Here is the code used to set up the navBar attributes:

 override func viewWillAppear(_ animated: Bool) {
    let textAttributes = [NSAttributedString.Key.foregroundColor:ThemeManager.shared.default1]
    self.navigationController?.navigationBar.largeTitleTextAttributes = textAttributes
    self.navigationController?.navigationBar.titleTextAttributes = textAttributes
    self.navigationController?.navigationBar.tintColor = ThemeManager.shared.default1
 self.navigationController?.setNavigationBarHidden(false, animated: true)
    self.navigationController?.navigationBar.prefersLargeTitles = true
    let nav = self.navigationItem
    nav.title = "My Profile"
}

Here are a couple of images showing the difference:

left, compiled on Xcode 10, right, Xcode 11 beta:

enter image description here enter image description here

Once you scroll up on the 11 Beta version, the background fades back in. Note that apps that are not compiled in Xcode 11 beta will still behave in the normal way, only changes after compiling for some reason. Is this intended, and how would I bring back the original behavior?

like image 640
Peter Ruppert Avatar asked Jun 06 '19 18:06

Peter Ruppert


2 Answers

This is intended behavior for iOS 13.

Apple's idea (terrible in my opinion) is that the title should merge with the content to show that it is related. Once you start scrolling, when content goes behind the title bar then the title bar will take the "correct" appearance.

The reason this is terrible is because everyone has currently planned all of their UI without this behavior. So the new behavior should be opt-in instead of forcing everyone to opt-out (i.e. the change breaks everyone's code and if you're going to break everyone's code at least you should be clear about how to keep the tried and true behavior of the last 10 years).

As in your case, the result looks horrible. The result looks horrible in my case too.

Apple doesn't give answers but says that you should be using

- scrollEdgeAppearance

From UINavigationBar in order to control the appearance of the bar when content is aligned top-of-content to bottom-of-navbar ... in my case this method returns nil though so I'm currently unsure how we're supposed to use this.

This seems to be discussed here as well:

New UINavigationBar appearance in detail pane of UISplitViewController in iOS 13

So the current workaround would seem to be this in your view controller:

- (void)viewDidLoad;
{
    [super viewDidLoad];
    if (@available(iOS 13,*)){
        UINavigationBar *bar =self.navigationController.navigationBar;
        bar.scrollEdgeAppearance = bar.standardAppearance;
    }
}

It works, but if it's the intended approach, I don't know...

EDIT:

Doing this does seem to block any additional direct customization to the UINavigationBar as has been noted. Possible that adjusting the scrollEdgeAppearance from here is the way to go. Ugly. Ugly. Ugly.

EDIT: Progress... this is working now for managing the background. You need to call this instead of setting barTint directly.

@interface UINavigationBar (Compatibility)
- (void)setCompatibleTint:(UIColor *)fg andBarTint:(UIColor *)bg;
@end

@implementation UINavigationBar (Compatibility)
- (void)setCompatibleTint:(UIColor *)fg andBarTint:(UIColor *)bg;
{
    self.tintColor = fg;
    self.barTintColor = bg;
    if (@available(iOS 13,*)){
        // we need to tell it to adopt old style behavior first
        UINavigationBarAppearance *appearance = self.standardAppearance;
        appearance.backgroundColor = bg;
        NSDictionary *attributes = self.titleTextAttributes;
        appearance.titleTextAttributes = attributes;
        attributes = self.largeTitleTextAttributes;
        appearance.largeTitleTextAttributes = attributes;
        self.scrollEdgeAppearance = appearance;
        self.standardAppearance = appearance;
        self.compactAppearance = appearance;
    }
}
@end

I'm not entirely sure yet on the text attributes but it seems to flow from the background color. It's a complete PITA.

It would be nicer to set this as a subclass and override barTint but of course a lot of the UIKit objects create these bars themselves so you won't get the subclass.

like image 146
dbquarrel Avatar answered Oct 03 '22 10:10

dbquarrel


Swift version of dbquarrel's solution.

First declare your textAttributes:

let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.red]

Use these in a UINavigationBarAppearance() to enable you to change the colour of the text in 3 different modes (scollEdge, standard and compact).

override func viewDidLoad() {
    super.viewDidLoad()
    if #available(iOS 13.0, *) {
        let appearance = UINavigationBarAppearance()
        appearance.largeTitleTextAttributes = textAttributes
        appearance.titleTextAttributes = textAttributes
        let bar = self.navigationController?.navigationBar
        bar?.scrollEdgeAppearance = appearance
        bar?.standardAppearance = appearance
        bar?.compactAppearance = appearance
    } else {
        // Fallback on earlier versions
    }
}
like image 23
Peter Ruppert Avatar answered Oct 03 '22 12:10

Peter Ruppert