作为一个iOS工程师,在项目中经常遇到需要设置导航栏的情况,有的时候是需要设置全局导航栏,有的时候需要单独的定义某个页面的导航栏。通过本篇文章,我们来讨论以下问题:
- 导航栏遮挡的问题
- 导航栏背景设置和分割线设置
- 如何设置全局返回按钮
- 如何控制导航栏的高度
- 如何添加全局返回手势
- 如何设置单个控制器的导航栏
导航栏遮挡的问题
iOS7
后默认情况下,导航栏会遮挡ViewController
的内容。这个原因是由于导航栏的半透明translucent
属性造成的。(想要有半透明效果,那导航栏后边要有东西啊,要不然怎么看出来半透明效果)。知道原因那我们就知道该怎么修改了。将导航栏的translucent
属性设为NO
就可以了。
[[UINavigationBar appearance] setTranslucent:NO];
那除了这这种方法还有其他方法解决这个问题么?
我又从UIViewController
的接口文档中,我找到了一下API:
@property(nonatomic,assign) UIRectEdge edgesForExtendedLayout NS_AVAILABLE_IOS(7_0); // Defaults to UIRectEdgeAll
@property(nonatomic,assign) BOOL extendedLayoutIncludesOpaqueBars NS_AVAILABLE_IOS(7_0); // Defaults to NO, but bars are translucent by default on 7_0.
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets NS_AVAILABLE_IOS(7_0); // Defaults to YES
从这些属性中我找到了其他办法。
- 我们将
edgesForExtendedLayout
的值设置为UIRectEdgeNone
的时候,控制器视图的顶端会向下移动到导航栏的底部。这个属性和导航的translucent
属性是没有关系的。这个属性只对子控制器有效,对容器控制器无效。 -
extendedLayoutIncludesOpaqueBars
从属性名称中我们可以看出这个属性是用来控制布局时是否包含透明Bar。这个属性是和NavBar和Tabbar的translucent
属性是有关系的。这个属性只有当他们的translucent
属性为NO
时,这个属性才有用。当extendedLayoutIncludesOpaqueBars = YES
时。布局是从屏幕顶端(底部)开始的,会被导航栏(或TabBar)遮挡。当extendedLayoutIncludesOpaqueBars = NO
时,布局是从导航栏底部(或TabBar顶部)开始的,不会被导航栏(或TabBar)遮挡。 -
automaticallyAdjustsScrollViewInsets
属性是用来控制容器视图控制器中的子控制器的可滚动区域插值的。例如当导航栏中的某个控制器视图是一个全屏UITableView
,则会在UITableView
的上下自动插入NavBar和Tabbar的的高度
@interface UIViewController (UILayoutSupport)
// These objects may be used as layout items in the NSLayoutConstraint API
@property(nonatomic,readonly,strong) id<UILayoutSupport> topLayoutGuide NS_AVAILABLE_IOS(7_0);
@property(nonatomic,readonly,strong) id<UILayoutSupport> bottomLayoutGuide NS_AVAILABLE_IOS(7_0);
@end
从接口文档中,我们得知这个用来做布局的。
官方还给了一个例子:
[button setTranslatesAutoresizingMaskIntoConstraints: NO];
id topGuide = myViewController.topLayoutGuide;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings (button, topGuide);
[myViewController.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat: @"V:[topGuide]-20-[button]"
options: 0
metrics: nil
views: viewsDictionary]];
[self.view layoutSubviews]; // You must call this method here or the system raises an exception
这两个属性是实现了<UILayoutSupport>
协议的。从这个协议中我们可以得到length
,也就是高度。这两个属性和NavBar和Tabbar
的translucent
属性是有关系的。只有当他们的translucent = YES
时,他们的length
才会返回对应的高度。否则length = 0
。
导航栏背景设置和分割线设置
导航栏背景
- 可以通过
barTintColor
来设置NavBar的颜色。
@property(nullable, nonatomic,strong) UIColor *barTintColor NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR; // default is nil
- 可以通过背景图片来设置。
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
隐藏分割线(阴影线)
@property(nullable, nonatomic,strong) UIImage *shadowImage NS_AVAILABLE_IOS(6_0) UI_APPEARANCE_SELECTOR;
通过将shadowImage
属性设为一个空的UIImage
来实现隐藏分割线的效果。前提是导航栏的背景是用图片来设置的。当然还有其他方法,比如通过遍历NavBar的子视图来找到这个分割线,然后删除或隐藏,但我还是觉得这种方法是最简单快捷的。
如何设置全局返回按钮
设置返回按钮的图片
[[UINavigationBar appearance] setBackIndicatorImage:baceImage];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:baceImage];
设置返回按钮的文字
- 方案一:继承UINavigationController
//重写方法
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
[super pushViewController:viewController animated:animated];
viewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"" style:(UIBarButtonItemStylePlain) target:nil action:nil];
}
- 方案二:实现
<UINavigationControllerDelegate>
协议
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
viewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:(UIBarButtonItemStylePlain) target:nil action:nil];
}
如何控制导航栏的高度
添加UINavigationBar
的Category
重载sizeThatFits
方法或者继承UINavigationBar
重写sizeThatFits
属性。
- (CGSize)sizeThatFits:(CGSize)size{
return (CGSize){
[UIScreen mainScreen].bounds.size.width,70
};
}
如何添加全局返回手势
一个丝滑的全屏滑动返回手势
FDFullscreenPopGesture
这个库不用一行代码就可以给UINavigationController
添加了全屏滑动返回手势。并且非常完美的实现了指定控制器导航栏隐藏的问题。可以对指定控制器隐藏导航栏和关闭全屏滑动返回手势。
如何设置单个控制器的导航栏
利用FDFullscreenPopGesture,隐藏指控制器的导航栏,然后添加自定义的导航栏,来完成我们想要的效果,比如滑动动画隐藏或其他效果。
网友评论