Reputation: 6475
I need to add a border underneath UIInavigationBar
and I also want it to be global thing, so I go to my top hierarchy UIViewController
and put there a method similiar to this one:
- (void)setupNavigationBarBorder {
if (![self isKindOfClass:[CombinedViewController class]]) {
CGRect borderRect = CGRectMake(0, self.navigationController.navigationBar.frame.size.height-0.5f, self.navigationController.navigationBar.frame.size.width, 0.5f);
CALayer *border = [CALayer layer];
border.frame = borderRect;
border.name = @"border";
[border setBackgroundColor:[UIColor greenColor].CGColor];
[self.navigationController.navigationBar.layer addSublayer:border];
} else {
NSArray* sublayers = [NSArray arrayWithArray:self.navigationController.navigationBar.layer.sublayers];
for (CALayer *layer in sublayers) {
if ([layer.name isEqualToString:@"border"]) {
[layer removeFromSuperlayer];
}
}
}
}
Which is a simple trigger for drawing and removing this sublayer. Pretty straightforward. So at first I've decided I'll put this code in viewDidLoad
, but it turned out it's not the best idea, since I'm actually modifying global state of UINavigationBar
. Next step was putting this method call to viewWillAppear
and most of the time it's okay, but when I move from this ComboFeedViewController
to the one that should have this border... Well, it gets drawn instantly.
I want it to be shown just when the transition is over or in the best case scenario, appear with transition. How Can I achieve this?
Upvotes: 0
Views: 648
Reputation: 6475
While approved answer seems to fix my problem I have faced some issues with transitioning from specific views of my app. Mostly because viewVillAppear
is triggered immediately when the swipe back gesture begins.
The defect was so small, that wasn't even worth spending a big amount of time on it, but it was still somewhere in my head, so... I've found a library named KMNavigationBarTransition
which swizzles methods and because of this you're able to set different navigation bar appearance for each view controller - which is exactly what I was looking for.
Right now I can simply put my showBorder
and hideBorder
cusstom methods in viewDidLoad
of specific View Controllers and everything works perfectly! 👌
Upvotes: 0
Reputation: 725
Please have a look at Apple's Customizing UINavigationBar sample code. The example's there cover a lot of ground in terms of customizing the navigation bar.
If you want to visually modify a navigation bar, but only have that modification visible in one of the screens in a navigation stack, then your best bet is to hook into these two methods:
viewWillAppear:
for modifying something in the barviewWillDisappear:
for hiding that modificationThe didAppear or didDisappear methods could also work for you. But I find that hooking into the willAppear/willDisappear variants and respecting the animated parameter worked wonders for me.
Here's sample code taken out of one of my projects that hides the hairline (the border) below the navigation bar (useful if you want to stick a UIToolbar below the UINavigationBar in one of the screens, to have a double sized bar):
class ViewController: UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// We need to hide the hairline, so the bar appears
// continous with the toolbar below it.
navigationController?.navigationBar.setHairlineEnabled(false, animated: animated)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.navigationBar.setHairlineEnabled(true, animated: animated)
}
}
extension UINavigationBar {
/// Hides the hairline below the navigation bar by walking
/// the subview hierarchy and finding a 0.5 or 1 pt tall view.
func setHairlineEnabled(enabled: Bool, animated: Bool) {
guard subviews.count > 0 else { return }
let firstSubview = subviews[0]
for subview in firstSubview.subviews {
let height = subview.bounds.height
if height == CGFloat(0.5) || height == CGFloat(1.0) {
let work = {
subview.alpha = enabled ? CGFloat(1) : CGFloat(0)
}
if animated {
UIView.animateWithDuration(NSTimeInterval(UINavigationControllerHideShowBarDuration), animations: {
work()
})
} else {
work()
}
break
}
}
}
}
Upvotes: 2