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.
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
}
}
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]];
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With