iPhone有一个回退按钮在所有的导航条上.这是一个简单的没有文字箭头.
在一开始写项目的时候,就要做好一个准备,导航栏是自定义还是使用系统的,后期有什么改动,有什么比较特殊的需求、当然这些在更改需求的同时,很多东西都已经被改得面目全非了。
完全自定义导航栏,在实际开发中,并不能满足特殊需求,因此更多情况下,还是需要配合系统导航栏自定义,从而达到我们想要的效果。当我们自定义返回按钮之后,就会出现系统的右滑Pop功能就失效了,这是其中的一个小问题,下面就跟大家分享一下我所了解到的:
实现一个自定义按钮是简单的.类似这个设置controller 的navigationItem一个leftBarButtonItem.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 文/煜寒了(简书作者) 2 原文链接:http://www.jianshu.com/p/349636eb3fca 3 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。 4 5 - (void)viewDidLoad 6 { 7 self.navigationItem.leftBarButtonItem = [self backButton]; 8 } 9 10 - (UIBarButtonItem *)backButton 11 { 12 UIImage *image = [UIImage imageNamed:@"back_button"]; 13 CGRect buttonFrame = CGRectMake(0, 0, image.size.width, image.size.height); 14 15 UIButton *button = [[UIButton alloc] initWithFrame:buttonFrame]; 16 [button addTarget:self action:@selector(backButtonPressed) forControlEvents:UIControlEventTouchUpInside]; 17 [button setImage:[UIImage imageNamed:normalImage] forState:UIControlStateNormal]; 18 19 UIBarButtonItem *item; = [[UIBarButtonItem alloc] initWithCustomView:button]; 20 21 return item; 22 }
但是这样在iOS7上 pop手势交互就不好使了.我发现了一个轻松解决的办法.通过我的beta测试者,我收到了很多关于pop手势的崩溃日志.我发现在栈中推入一个controller后,快速向左平滑,将会引起崩溃.换句话说,如果用户在推入还在进行的时候立即去点击返回.那么导航控制器就秀逗了.我在调试日志里面发现这些:
nested pop animation can result in corrupted navigation bar
经过几个小时的奋斗和尝试,我发现可以缓解这个错误:设置手势的delegate为这个导航控制器就像Stuart Hall在他的帖子说的那样,分配了一个手势交互行为的委托在自定义按钮显示的时候.然后,当用户快速点击退出的时候,控制器因为手势发送了一个消息在本身已经被销毁的时候.我的解决方案是简单的让NavigationController自己成为响应的接受者.最好用一个UINavigationController的子类.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 文/煜寒了(简书作者) 2 原文链接:http://www.jianshu.com/p/349636eb3fca 3 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。 4 5 @interface CBNavigationController : UINavigationController <UIGestureRecognizerDelegate> 6 @end 7 8 @implementation CBNavigationController 9 10 - (void)viewDidLoad 11 { 12 __weak CBNavigationController *weakSelf = self; 13 14 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) 15 { 16 self.interactivePopGestureRecognizer.delegate = weakSelf; 17 } 18 } 19 20 @end
在转场/过渡的时候禁用 interactivePopGestureRecognizer当用户在转场的时候触发一个后退手势,则各种事件又凑一块了.导航栈内又成了混乱的.我的解决办法是,转场效果的过程中禁用手势识别,当新的视图控制器加载完成后再启用.再次建议使用UINavigationController的子类操作.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 文/煜寒了(简书作者) 2 原文链接:http://www.jianshu.com/p/349636eb3fca 3 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。 4 5 @interface CBNavigationController : UINavigationController <UINavigationControllerDelegate, UIGestureRecognizerDelegate> 6 @end 7 8 @implementation CBNavigationController 9 10 - (void)viewDidLoad 11 { 12 __weak CBNavigationController *weakSelf = self; 13 14 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) 15 { 16 self.interactivePopGestureRecognizer.delegate = weakSelf; 17 self.delegate = weakSelf; 18 } 19 } 20 21 // Hijack the push method to disable the gesture 22 23 - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated 24 { 25 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) 26 self.interactivePopGestureRecognizer.enabled = NO; 27 28 [super pushViewController:viewController animated:animated]; 29 } 30 31 #pragma mark UINavigationControllerDelegate 32 33 - (void)navigationController:(UINavigationController *)navigationController 34 didShowViewController:(UIViewController *)viewController 35 animated:(BOOL)animate 36 { 37 // Enable the gesture again once the new controller is shown 38 39 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) 40 self.interactivePopGestureRecognizer.enabled = YES; 41 } 42 43 44 @end
2015-07-21 更新 解决左滑手势冲突和不灵敏的问题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 文/煜寒了(简书作者) 2 原文链接:http://www.jianshu.com/p/349636eb3fca 3 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。 4 5 -(UIViewController *)popViewControllerAnimated:(BOOL)animated { 6 7 return [super popViewControllerAnimated:YES]; 8 } 9 10 #pragma mark UINavigationControllerDelegate 11 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { 12 if ([self.childViewControllers count] == 1) { 13 return NO; 14 } 15 return YES; 16 } 17 18 // 我们差不多能猜到是因为手势冲突导致的,那我们就先让 ViewController 同时接受多个手势吧。 19 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 20 { 21 return YES; 22 } 23 //运行试一试,两个问题同时解决,不过又发现了新问题,手指在滑动的时候,被 pop 的 ViewController 中的 UIScrollView 会跟着一起滚动,这个效果看起来就很怪(知乎日报现在就是这样的效果),而且也不是原始的滑动返回应有的效果,那么就让我们继续用代码来解决吧 24 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 25 { 26 return [gestureRecognizer isKindOfClass:UIScreenEdgePanGestureRecognizer.class]; 27 } 28 29 -(UIViewController *)popViewControllerAnimated:(BOOL)animated { 30 31 return [super popViewControllerAnimated:YES]; 32 } 33 34 #pragma mark UINavigationControllerDelegate 35 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { 36 if ([self.childViewControllers count] == 1) { 37 return NO; 38 } 39 return YES; 40 } 41 42 // 我们差不多能猜到是因为手势冲突导致的,那我们就先让 ViewController 同时接受多个手势吧。 43 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 44 { 45 return YES; 46 } 47 //运行试一试,两个问题同时解决,不过又发现了新问题,手指在滑动的时候,被 pop 的 ViewController 中的 UIScrollView 会跟着一起滚动,这个效果看起来就很怪(知乎日报现在就是这样的效果),而且也不是原始的滑动返回应有的效果,那么就让我们继续用代码来解决吧 48 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 49 { 50 return [gestureRecognizer isKindOfClass:UIScreenEdgePanGestureRecognizer.class]; 51 }