iOS Navigation导航栏
在iOS开发过程中,导航栏是最为经常用到的控件,处理不好总会出现一些瑕疵或者bug,写这篇文章旨在为自己记录平时所用有关Navigation一些操作或者说是小技巧。
下文涉及到的push逻辑都是从A页面push到B页面,我会直接以A、B介绍
一、关于返回Item
默认从A—>B(push),B中返回按钮的title显示的是A的标题,当A的标题过长,会显示返回(back)。A标题长同时B标题也长,就会出现B标题被挤到右边了,这就尴尬了。如下图
B标题未正常显示
网上有说在A的viewWillDisappear将A的标题设置成空的,在viewDidAppear方法中再将标题设置原来的,但是这个在手势侧滑过程中显示会有问题,这里就不做演示了。
这里提供一个解决方案:让A控制器继承自BaseViewController(自己创建的控制器),在BaseViewController做以下操作:
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"返回"
style:UIBarButtonItemStyleDone
target:self
action:nil];
self.navigationItem.backBarButtonItem = backItem;
}
正常显示
有时我们并不需要显示title,在上图中的“返回”设置成 nil 就可以解决问题。当然我们刚才并没有改变返回的图片都是用系统默认的,如果只是单纯的显示自定义的返回图标(需求就是这么样,有什么办法),那么问题来了,怎么设置比较合理。以
下给出几种方案:
1、设置navigationItem的leftBarButtonItem(不推荐)
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"navigation_back"]
style:UIBarButtonItemStylePlain
target:self
action:@selector(p_actionBack)];
self.navigationItem.leftBarButtonItem = backItem;
自定义返回按钮
只是添加leftBarButtonItem侧滑手势被禁止了,图标离左侧有一定距离,经过如下修改:
- (void)p_addBackItem {
//间隙
UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:self action:nil];
//spaceItem宽度为负值,相当于左移
spaceItem.width = -8;
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"navigation_back"]
style:UIBarButtonItemStylePlain
target:self
action:@selector(p_actionBack)];
self.navigationItem.leftBarButtonItems = @[spaceItem, backItem];
//设置代理,添加leftBarButtonItem系统的侧滑手势会被禁
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
- (void)p_actionBack {
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
自定义
2、将title移出视图外,从而达到隐藏的效果(推荐,作用范围全局)
注意:这个需要在AppDelegate设置才有效
- (void)initBars {
UIImage *backImage = [UIImage imageNamed:@"navigation_back"];
UINavigationBar *navigationbar = [UINavigationBar appearance];
[navigationbar setBackIndicatorImage:backImage];
[navigationbar setBackIndicatorTransitionMaskImage:backImage];
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
forBarMetrics:UIBarMetricsDefault];
}
设置偏移量,替换系统返回按钮
上一页标题过长
对比可以发现,第一张图是标题比较短的时候显示正常,第二张图是标题比较长的时候标题被往右挤了。
视图下查看 这个方法只是将返回Item的title移出,宽度并没有改变,所以在使用这个方法时一定要注意,我一般是配合一开始提到的搭配使用。如果有更好的解决方法可以留言告知,不胜感激。
二、Navigation显示或隐藏
项目中一般有一两个页面比较特殊,需要隐藏导航栏或者导航栏需要根据滑动渐变,如登录页面需要隐藏导航栏。隐藏简单,拿起键盘就是干。
1、隐藏导航栏
使用[self.navigationController setNavigationBarHidden:NO animated:YES] 侧滑手势会被禁,所以需要加代理开启手势
- (void)viewDidLoad {
[super viewDidLoad];
//设置代理
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//会导致侧滑手势被禁
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//如果该控制器没有上级控制器,建议将使用[self.navigationController setNavigationBarHidden:NO animated:animated] 效果会更好点
[self.navigationController setNavigationBarHidden:NO animated:NO];
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
2、导航栏渐变
介绍两个方法:
//隐藏导航栏,但不隐藏上面的Item
[self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init]
forBarMetrics:UIBarMetricsDefault];
//隐藏导航栏底部那条线
[self.navigationController.navigationBar setShadowImage:[[UIImage alloc] init]];
这个不做演示,推荐一个三方 LTNavigationBar
三、自定义TitleView
直接上代码
UIView *titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 40)];
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
switchView.center = titleView.center;
[titleView addSubview:switchView];
self.navigationItem.titleView = titleView;
自定义TitleView