今天遇到需要修改navigationController的返回按钮的图标的需求,网上提供了在controller的viewDidAppear方法中去修改返回按钮为自定义的类型,但是这样做并不是一个完美的解决办法,所以写下来方便后来的人
首先需要自定义UINavigationController,并成为自己的代理,在willShowViewController方法中隐藏原本的返回按钮,并添加自定义的item,并将UIButton作为自定义view嵌套进item中,同时为了偏移按钮的位置,还需要添加一个UIBarButtonSystemItemFixedSpace类型的barButtonItem,这个控件可以偏移返回按钮的位置
#pragma mark -UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
// 如果是根视图,则不添加返回按钮
if (viewController == self.childViewControllers[0] || viewController.navigationItem.hidesBackButton) {
return;
}
// 隐藏系统默认返回按钮
viewController.navigationItem.hidesBackButton = true;
// 定义自定义的button,设置图片为自己想设置的返回按钮图片,并嵌套进一个UIBarButtonItem中
UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 35, 35)];
[backButton setBackgroundImage:[UIImage imageNamed:@"返回"] forState:UIControlStateNormal];
[backButton addTarget:self action:@selector(backBarButtonItemClicked) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backItem = [[UIBarButtonItem alloc]initWithCustomView:backButton];
// 再创建一个空白的UIBarButtonItem,通过设置他的宽度可以偏移其右侧的返回按钮的位置
UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spaceItem.width = -10;
// 将两个UIBarButtonItem设置给当前的VC
viewController.navigationItem.leftBarButtonItems = @[spaceItem,backItem];
}
同时不要忘记给自己创建的返回按钮添加一个监听事件
#pragma mark -private func
- (void)backBarButtonItemClicked{
[self popViewControllerAnimated:true];
}
但是这样就没有返回手势了,需要恢复返回手势
在navigationCotroller的viewDidLoad方法中添加如下代码
// 修复没有返回手势的问题
__weak typeof(self) weakSelf= self;
if([self respondsToSelector:@selector(interactivePopGestureRecognizer)]){
self.interactivePopGestureRecognizer.delegate = weakSelf;
}
为了防止在push的过程中触发pop事件导致崩溃,需要在push的时候禁用pop手势
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
// 防止在push的时候触发pop手势导致导航栏崩溃
// 如果当前正在pop,则禁用手势
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.interactivePopGestureRecognizer.enabled = false;
}
[super pushViewController:viewController animated:animated];
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
// 修复没有返回手势的问题
if([self respondsToSelector:@selector(interactivePopGestureRecognizer)]){
self.interactivePopGestureRecognizer.enabled = true;
}
}
现在我们有了返回手势了,但是另一个问题出现了,在手势触发的时候在navBar的左边或中间会出现一个label,如果手势完全完成还好,如果要是触发手势了但是没有让页面pop,navBar上就会出现一个为 ··· 的label
遍历了windows的subviews,发现了一个可疑的按钮好像与这个有关
for (UIView *view in [UIApplication sharedApplication].keyWindow.subviews) {
[HBShareTool allView:view];
}
NSLog(@"~~~~~~~~~~~");
+ (void)allView:(UIView *)superView{
for (UIView *subView in superView.subviews) {
[HBShareTool allView:subView];
if (subView.class == [UILabel class]) {
NSLog(@"title:%@",[(UILabel *)subView text]);
if ([[(UILabel *)subView text] isEqualToString:@"Back"]) {
[(UILabel *)subView setText:@""];
}
subView.x += 10;
}
if (subView.class == [UIButton class]) {
NSLog(@"button title:%@",[(UIButton *)subView titleLabel].text);
subView.x += 10;
}
}
}
2016-01-12 14:18:04.362 CreaTee[1128:642104] title:FRAME
2016-01-12 14:18:04.362 CreaTee[1128:642104] title:FONT
2016-01-12 14:18:04.362 CreaTee[1128:642104] title:GRAFFITI
2016-01-12 14:18:04.363 CreaTee[1128:642104] title:PUZZLE
2016-01-12 14:18:04.363 CreaTee[1128:642104] title:DESIGNER TECOMMEND
2016-01-12 14:18:04.365 CreaTee[1128:642104] title:START DIY
2016-01-12 14:18:04.366 CreaTee[1128:642104] title:公牛字母T恤
2016-01-12 14:18:04.366 CreaTee[1128:642104] title:@MONSTER
2016-01-12 14:18:04.366 CreaTee[1128:642104] title:¥79元
2016-01-12 14:18:04.367 CreaTee[1128:642104] title:NEW/新品
2016-01-12 14:18:04.367 CreaTee[1128:642104] title:内部价:48元
2016-01-12 14:18:04.368 CreaTee[1128:642104] title:公牛字母T恤
2016-01-12 14:18:04.368 CreaTee[1128:642104] title:@MONSTER
2016-01-12 14:18:04.369 CreaTee[1128:642104] title:¥79元
2016-01-12 14:18:04.369 CreaTee[1128:642104] title:NEW/新品
2016-01-12 14:18:04.370 CreaTee[1128:642104] title:内部价:48元
2016-01-12 14:18:04.370 CreaTee[1128:642104] title:复仇者联盟(共31件)
2016-01-12 14:18:04.370 CreaTee[1128:642104] title:Back
2016-01-12 14:18:04.372 CreaTee[1128:642104] button title:(null)
2016-01-12 14:18:04.373 CreaTee[1128:642104] button title:(null)
2016-01-12 14:18:04.374 CreaTee[1128:642104] button title:(null)
2016-01-12 14:18:04.375 CreaTee[1128:642104] button title:(null)
2016-01-12 14:18:04.376 CreaTee[1128:642104] button title:(null)
2016-01-12 14:18:04.377 CreaTee[1128:642104] button title:(null)
通过排除法,最可疑的就是为Back的title,这个按钮应该是navController的返回按钮的title,解决办法就是在navController的didShow代理方法中设置一下返回按钮的title
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:self action:nil];
viewController.navigationItem.backBarButtonItem = barButtonItem;
但是我们已经把他隐藏了,为什么还会出现在屏幕上呢?
估计有可能两个原因:
1.因为用了系统自带的返回手势,而手势响应的某些方法影响了backItem的隐藏属性,导致手势触发的时候系统的返回按钮被显示出来,或被添加到navBar上了。
2.当根层级的VC在画面上出现的时候,由于其backItem没有被隐藏,所以nav认为rootVC已经出现了,则取消了backItem的显示,但其实这时候我们的当前VC并没有被POP,而是刚刚触发手势的状态,这时候如果将当前VC放回原位,由于backItem已经被显示了,而且隐藏只是一个状态,并不会因为手势的取消而改变,出现的同时,页面上已经没有它的位置了,所以被显示为"···",因为宽度不够。也就是说,跟层级的VC的“出现”让系统以为我们要进行pop了,所以提前将rootVC的nav属性赋给了navBar,但实际情况是时机还没有到。
以上是两点我估测的结果,各位如果有正确答案欢迎指正。