Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 11 Large Title change event

I want to get the event when iOS 11 large title changes. i.e. When it changes the place to & from navigation bar when user scrolls the view. I've checked the UINavigationBar class but nothing I can get it from.

The screen design I want to implement is like when Large title is visible I want transparent Navigation bar but when title scrolled up to navigation bar I want nav bar with solid colour.

like image 767
Piyush Hirpara Avatar asked Feb 20 '18 12:02

Piyush Hirpara


3 Answers

It can done by getting current height of UINavigationBar by scrollViewDidScroll func.

func scrollViewDidScroll(_ scrollView: UIScrollView) {

    //Get current height of navigation bar when tableview/collectionview/scrollview did scroll
    guard let navBarHeight = navigationController?.navigationBar.frame.height else {
        return
    }

    //Compare with standard height of navigation bar.
    if navBarHeight > 44.0 {
        self.navigationController?.navigationBar.shadowImage = UIImage()
        self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        self.navigationController?.navigationBar.barTintColor = .clear
    } else {
        self.navigationController?.navigationBar.shadowImage = nil
        self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
        self.navigationController?.navigationBar.barTintColor = .green
    }
}
like image 76
Jay Patel Avatar answered Nov 13 '22 09:11

Jay Patel


I have added this observer in my UIViewController's subclass's ViewWillAppear. and setting the color according to its height as below:

In ViewWillAppear:

UINavigationBar *navBar = self.navigationController.navigationBar;
[navBar addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];

In viewWillDisappear:

UINavigationBar *navBar = self.navigationController.navigationBar;
[navBar removeObserver:self forKeyPath:@"frame" context:NULL];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:@"frame"]) {
    [self setNavigationBarColour];;
}

}

- (void)setNavigationBarColour
{
    UINavigationBar *navBar = self.navigationController.navigationBar;
    CGFloat height = navBar.bounds.size.height;
    if(height>44)
    {
        [navBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
        [navBar setTranslucent:YES];
        [navBar setShadowImage:[UIImage new]];
    }
    else
    {
        [navBar setBackgroundImage:[[UINavigationBar appearance] backgroundImageForBarMetrics:UIBarMetricsDefault] forBarMetrics:UIBarMetricsDefault];
        [navBar setTranslucent:NO];
        [navBar setShadowImage:[[UINavigationBar appearance] shadowImage]];
    }
}
like image 4
Piyush Hirpara Avatar answered Nov 13 '22 08:11

Piyush Hirpara


A small improvement on Piyush Hirpara answer (regarding performances), is to subclass your navigationBar and only update on layoutSubviews:

class ObservingLargeTitleNavigationBar: UINavigationBar {

    override func layoutSubviews() {
        super.layoutSubviews()

        updateLargeTitle()
    }

    private func updateLargeTitle() {
        if #available(iOS 11.0, *) {
            if frame.height > 44 {
                // code logic when large title is visible
            } else {
                // code logic when large title is hidden
            }
        }
    }
}

Note that the value of 44 for the frame.height may need to be adjusted in some circumstances. I have it at 60 for instance in my configuration on an iPhone X.

like image 2
Cœur Avatar answered Nov 13 '22 08:11

Cœur