iOS 11 - UINavigationItem titleView when using Large Titles mode
Asked Answered
E

2

13

I'm trying to understand either it's a bug or it's the expected behavior.

On iOS 10 and earlier we could set up a custom title, using navigationItem.titleView.
On iOS 11, when setting our navigationItem.largeTitleDisplayMode = .always and setting navigationItem.titleView = <Some cool UIButton> it's displaying both the normal navigation title bar and the large navigation title.

Illustration: enter image description here

To sum up:

How can we use custom titleView on our Large Navigation Title?

EDIT : This is the expected result:

enter image description here

Ernestinaernestine answered 26/9, 2017 at 23:46 Comment(3)
"How can we use custom titleView on our Large Navigation Title?" You're doing it. That's the whole point! Previously, you could not have both a title and a title view. Now you can. Don't worry, be happy.Incredulous
@Incredulous I understand that. But I'm looking for the option to change the large title using custom views. Updated the expected resultErnestinaernestine
Well, stop expecting that result! You’ve misunderstood this feature.Incredulous
K
4

I was able to replace the navigation bar big title with a custom view by using a subclass of UINavigationBar and manually changing the view hierarchy :

@interface MYNavigationBar : UINavigationBar

@end
@implementation MYNavigationBar

// ...

- (void)layoutIfNeeded
{
    [self setupTitle];
    [super layoutIfNeeded];
}

- (void)setupTitle
{
    // UINavigationBar
    // -> ...
    // -> _UINavigationBarLargeTitleView
    //   -> UILabel << Big Title Label
    //   -> UIView
    //     -> UILabel << Big Title Label animating from back button during transitions

    for (UIView *view in self.subviews) {
        NSString *className = NSStringFromClass(view.classForCoder);
        if ([className containsString:@"LargeTitleView"]) {
            for (UIView *view2 in view.subviews) {
                if ([view2 isKindOfClass:[UILabel class]]) {
                    [self convertLabel:(UILabel *)view2];
                }
                for (UIView *view3 in view2.subviews) {
                    if ([view3 isKindOfClass:[UILabel class]]) {
                        [self convertLabel:(UILabel *)view3];
                    }
                }
            }
        }
    }
}

- (void)convertLabel:(UILabel*)label
{
    // I kept the original label in the hierarchy (with the background color as text color)
    // and added my custom view as a subview. 
    // This allow the transformations applied to the original label to be also applied to mine.
}

Please note that Apple might reject your app because of this trick.

Kinescope answered 7/8, 2019 at 12:23 Comment(3)
Altho it might cause rejection, it's a great answer! Anyway seems like Apple won't change the private class names so quick, and if the UI looks good I bet they won't ever care. Great job!Ernestinaernestine
Want to know if you are able to submit the application to appstore with this change as the class name is privateOrthogenetic
I had no issue during the review however I can’t say it 100% safeKinescope
A
6

I can't find any documentation on this, so I played a bit. It seems in iOS 11, you won't be able to get that title to be a button and display large at the left.

I don't know if this is a bug or the expected result, as it seems to be a new feature. The latest (iOS 11) Human Interface Guidelines (HIG) discuss the larger title label as being a way to give the user clear context. The HIG also discuss space between buttons. However, there's no discussion of using a button as the title.


To recreate, I set up a Single View project. I embedded the view controller in a navigation controller.

In ViewController.swift's viewDidLoad, I added this code:

    let titleButton = UIButton(type: .roundedRect)
    titleButton.setTitle("Hello Button!", for: UIControlState.normal)

    let navController = parent as! UINavigationController

    navController.navigationBar.topItem!.title = "Hello???"
    navController.navigationBar.topItem!.titleView = titleButton
    navController.navigationBar.prefersLargeTitles = true

This ends up looking something like your example.

IF I:

  • set .title to empty string, or remark the line out: navbar is stretched, and no title text shows (or title text set in Interface Builder shows)

  • remark out .prefersLargeTitles, or set it to false: the navbar is the normal height, the button displays, but no title text displays.

  • remark out the titleView line, AND:

    • leave the .prefersLargeTitles set to true: the title text displays large at the left, and the navbar's height is stretched.
    • set the .prefersLargeTitles to false: the title text displays in the top center, and the navbar is normal height.

Update: link to sample project on GitHub

Alica answered 23/10, 2017 at 16:58 Comment(2)
Hey Leanne, nice investigation. So as far as I understand, it's impossible to achieve clickable large title? :\Ernestinaernestine
That’s what it looks like. You might try reporting it as a bug to Apple to see what they say. Feel free to link to my example as a demo, or fork it if you’d like to add more info of your own.Alica
K
4

I was able to replace the navigation bar big title with a custom view by using a subclass of UINavigationBar and manually changing the view hierarchy :

@interface MYNavigationBar : UINavigationBar

@end
@implementation MYNavigationBar

// ...

- (void)layoutIfNeeded
{
    [self setupTitle];
    [super layoutIfNeeded];
}

- (void)setupTitle
{
    // UINavigationBar
    // -> ...
    // -> _UINavigationBarLargeTitleView
    //   -> UILabel << Big Title Label
    //   -> UIView
    //     -> UILabel << Big Title Label animating from back button during transitions

    for (UIView *view in self.subviews) {
        NSString *className = NSStringFromClass(view.classForCoder);
        if ([className containsString:@"LargeTitleView"]) {
            for (UIView *view2 in view.subviews) {
                if ([view2 isKindOfClass:[UILabel class]]) {
                    [self convertLabel:(UILabel *)view2];
                }
                for (UIView *view3 in view2.subviews) {
                    if ([view3 isKindOfClass:[UILabel class]]) {
                        [self convertLabel:(UILabel *)view3];
                    }
                }
            }
        }
    }
}

- (void)convertLabel:(UILabel*)label
{
    // I kept the original label in the hierarchy (with the background color as text color)
    // and added my custom view as a subview. 
    // This allow the transformations applied to the original label to be also applied to mine.
}

Please note that Apple might reject your app because of this trick.

Kinescope answered 7/8, 2019 at 12:23 Comment(3)
Altho it might cause rejection, it's a great answer! Anyway seems like Apple won't change the private class names so quick, and if the UI looks good I bet they won't ever care. Great job!Ernestinaernestine
Want to know if you are able to submit the application to appstore with this change as the class name is privateOrthogenetic
I had no issue during the review however I can’t say it 100% safeKinescope

© 2022 - 2024 — McMap. All rights reserved.