叙述
ios中导航栏是一个很头疼的东西,因为navigationbar是统一设置,无法实现每个页面有自己的导航栏样式。解决的办法有两个,
1、隐藏系统自带的self.navigationViewController.navigationBar,在baseViewController中自己添加一个navigationBar,这样就可以在每个vc中设置自己的样式了
优点:各管各的,不会相互影响,使用方便
缺点:不会有过度渐变效果,每个页面都创建navigationBar,消耗稍微大点
2、在vc出现的时候时(viewWillAppear)重新设置导航栏样式
优点:系统原生,效率高,可自定义导航栏过渡动画效果
缺点:容易出坑
-----------------------------凌乱分割线-----------------------------
接下来以第二种方法为例,看看怎么设置导航栏样式:
1、修改导航栏背景颜色
默认导航栏只有两个样式:黑色毛玻璃和白色毛玻璃
[self.navigationController.navigationBar setBarStyle:UIBarStyleBlack];
设置导航栏的颜色:
[self.navigationController.navigationBar setBarTintColor:[UIColor blueColor]];
由于模式原因,会混上白色或者黑色蒙蔽+背景高斯模糊效果,所以设置的意思未必是你想要的真正颜色,网上有些颜色转换的方法,但是我试了都不是特别准,写一个相对好点的
- (UIColor *)barColorTransitionWithColor:(UIColor *)color {
CGFloat red, green, blue, alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
CGFloat opacity = 0.4;
CGFloat minVal = MIN(MIN(red, green), blue);
if ([self convertValue:minVal withOpacity:opacity] < 0) {
opacity = [self minOpacityForValue:minVal];
}
red = [self convertValue:red withOpacity:opacity];
green = [self convertValue:green withOpacity:opacity];
blue = [self convertValue:blue withOpacity:opacity];
red = MAX(MIN(1.0, red), 0);
green = MAX(MIN(1.0, green), 0);
blue = MAX(MIN(1.0, blue), 0);
return [UIColor colorWithRed:red green:green blue:blue alpha:1.];
}
- (CGFloat)minOpacityForValue:(CGFloat)value
{
return (0.4 - 0.4 * value) / (0.6 * value + 0.4);
}
- (CGFloat)convertValue:(CGFloat)value withOpacity:(CGFloat)opacity
{
return 0.4 * value / opacity + 0.6 * value - 0.4 / opacity + 0.4;
}
2.设置导航栏透明度
直接设置navigationBar的alpha是什么效果的,需要获取到navigation的subview,这里ios10的subview类名有所改变,所以要特殊处理
NSString *backgroundViewClass = @"_UINavigationBarBackground";
if (IOS10) {
backgroundViewClass = @"_UIBarBackground";
}
for (UIView * subView in self.subviews) {
if ([subView isKindOfClass:NSClassFromString(backgroundViewClass)]) {
[self setOverlay:subView];
return subView;
}
}
设置这个subview的alpha就能达到导航栏的透明度,而不影响导航栏上面item
3.控制导航栏分割线
同样可以遍历navbar的subview获取到分割线的view进行控制
- (UIImageView *)yxBottomLine:(UIView *)view
{
if ([view isKindOfClass:[UIImageView class]] &&
view.bounds.size.height <= 1.0)
{
return (UIImageView *)view;
}
for (UIView *subView in view.subviews)
{
UIImageView *imageView = [self yxBottomLine:subView];
if (imageView)
{
return imageView;
}
}
return nil;
}
4.修改导航栏item颜色:
[self.navigationController.navigationBar setTintColor:color];
5.修改导航栏标题样式:
NSDictionary *attributes=[NSDictionary dictionaryWithObjectsAndKeys:titleColor, NSForegroundColorAttributeName, [UIFont boldSystemFontOfSize:17], NSFontAttributeName, nil];
[self.navigationController.navgationBar setTitleTextAttributes:attributes];
6.添加导航栏过度渐变动画:
[[self transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
[self updateNavigationBarType:type];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
if (![context isCancelled]) {
[self updateNavigationBarType:type];
}
}];
在导航栏样式发送变化的时候放到这个函数里来,ps:ios10过度动画不理想,可以ios10参考第一中方法实现
7.自定义导航栏返回按钮图标
- (void)updateNavBackItemIcon {
[self.navigationController.navigationBar setBackIndicatorImage:[UIImage imageNamed:@"icon_navigation_back"]];
[self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"icon_navigation_back"]];
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes: @{NSFontAttributeName:[UIFont systemFontOfSize:15.0]}
forState:UIControlStateNormal];
}
我已经写好的导航栏样式库:https://github.com/Jonear/JNNavigation (欢迎大家使用)