前言今天有一个小需求。在点击导航栏的返回按钮之前,需要调用一个API,弹出一个UIAlertView来显示。根据用户的选择,是返回还是继续留在当前控制器。举个简单的例子,当点击导航栏左上角的返回按钮时,会调用我们的API提示是否知道,点击则返回,点击则返回留在当前控制器中。那么问题来了,导航自带的右滑返回手势不会在点击系统的返回按钮时无法处理,是自动的,所以我们得想办法把它改成leftBarButtonItem,但是用leftBarButtonItem将失去向右滑动返回的手势。鱼和熊掌不能兼得吗?我有自己的解决办法!我试着写了个demo验证有没有解决办法,尝试了以下四种方法:只有当前的controller遵从UIGestureRecognizerDelegate并设置代理为self将UIGestureRecognizerDelegate放在public基类中controller遵从并设置代理为self,然后子类重写代理方法将UIGestureRecognizerDelegate放置在公共导航类HYBNavigationController中,并将代理设置为导航类,然后重写push/pop相关的所有方法并将UIGestureRecognizerDelegate放置在公共导航类HYBNavigationController中并将agent设置为导航类,但只遵循-gestureRecognizerShouldBegin:代理方法解决方案一(不可行)解决方案一:只在当前controller中遵守UIGestureRecognizerDelegate并设置代理为self为什么不可行?当你不想测试时你怎么知道?很难综合考虑。所以我写了一个小demo来测试一下。我们在控制器中这样写:-(void)viewDidLoad{[superviewDidLoad];UIButton*button=[UIButtonbuttonWithType:UIButtonTypeCustom];[buttonsetTitle:@"return"forState:UIControlStateNormal];[buttonaddTarget:selfaction:@selector(onBack)forControlEvents:UIControlEventTouchUpInside];[buttonsizeToFit];[buttonsetTitleColor:[UIColorblueColor]forState:UIControlStateNormal];UIBarButtonItem*btnItem=[[UIBarButtonItemalloc]initWithCustomView:button];self.navigationItem.leftBarButtonItem=btnItem;//关键行self.interactiveRecogizerGleres.navigationControlleres.delegate=self;}一旦代理设置为self,使用leftBarButtonItem后就可以实现点击回调,右滑手势依旧。但是,作为导航控制器对象代理的self.navigationController被修改为控制器对象。释放控制器类时,代理为零,因此不再有右滑返回手势。.那么有人可能会想,在-viewDidAppear:中设置代理为self,在-viewDidDisappear:中设置代理为原来的代理对象?同样是不可能的。当A推送给B,B推送给C,再从C返回时,agent就不再是原来的导航agent了。因此,该方案不可行。方案二(不可行)方案二:将UIGestureRecognizerDelegate放在public基类controller中并设置代理为self,然后子类重写代理方法。我尝试将UIGestureRecognizerDelegate放在HYBBaseViewControlle中遵守,然后实现代理,默认返回YES。表示支持向右滑动返回。如果你想让一个不支持右滑的控制器返回或者在返回前执行一些操作,你可以通过覆盖这个代理方法来实现。当仅在一个控制器中时,这是可以实现的。但是当controller被释放的时候,proxy对象就变成了nil,所以这个proxy是针对导航栏对象的,而不是针对单个controller的。方案三(可行,但复杂)方案三:将UIGestureRecognizerDelegate放在公共导航类HYBNavigationController中遵守,并将代理设置为导航类,然后重写所有push/pop相关方法。如何实现://HYBNavigationController.m//NavRightPanGestureDemo////Createdbyhuangyibiaon16/2/22.//Copyright?2016huangyibiao.Allrightsreserved.//#import"HYBNavigationController.h"#import"HYBBaseViewController.h"@interfaceHYBNavigationController()@property(nonatomic,assign)BOOLenableRightGesture;@end@implementationHYBNavigationController-(void)viewDidLoad{[superviewDidLoad];self.enableRightGesture=YES;self.interactivePopGestureRecognizer.delegate=self;}-(BOOL)gesturenRecognizerRecogniz*)gestureRecognizer{returnself.enableRightGesture;}-(void)pushViewController:(UIViewController*)viewControlleranimated:(BOOL)animated{if([viewControllerisKindOfClass:[HYBBaseViewControllerclass]]){if([viewControllerrespondsToSelector:@selector(gestureRecognizerHYBegin)])ControlBaseView*vc=(HYBBaseViewController*)viewController;self.enableRightGesture=[vcgestureRecognizerShouldBegin];}}[superpushViewController:viewControlleranimated:YES];}-(NSArray*)popToRootViewControllerAnimated:(BOOL)animated{self.enableRightGesture=YES;return[superpopToRootViewControllerAnimated:animated];}-(UIViewController*)popViewControllerAnimated:(BOOL)animated{if(self.viewControllers.count==1){self.enableRightGesture=YES;}else{NSUIntegerindex=self.viewControllers.count-2;UIViewController*destinationController=[self.viewControllersobjectAtIndex:index];if([destinationControllerisKindOfClass:[HYBBaseViewControllerclass]]){if([destinationControllerrespondsToSelector:@selector(gestureRecognizerShouldBegin)]){HYBBaseViewController*vc=(HYBBaseViewController*)destinationController;self.enableRightGesture=[vcgestureRecognizerShouldBegin];}}}返回[superpopViewControllerAnimated:animated];}-(NSArray*)popToViewController:(UIViewController*)viewControlleranimated:(BOOL)animated{if(self.viewControllers.count==1){self.enableRightGesture=YES;}else{UIViewController*destinationController=viewController;if([destinationControllerisKindOfClass:[HYBBaseViewControllerclass]]){if([destinationControllerrespondsToSelector:@selector(gestureRecognizerShouldBegin)]){HYBBaseViewController*vc=(HYBBaseViewController*)destinationController;自我。:viewControlleranimated:animated];}@end这个是通过重写所有pop/push相关的方法,判断是否支持右滑来设置的然后,我们要一个controller类在向右滑动或者点击返回之前调用我们的API判断,如下:];[buttonsetTitle:@"Return"forState:UIControlStateNormal];[buttonaddTarget:selfaction:@selector(onBack)forControlEvents:UIControlEventTouchUpInside];[buttonsizeToFit];[buttonsetTitleColor:[UIColorblueColor]forState:UIControlStateNormal];Ite*btnItem=[[UIBarButtonItemalloc]initWithCustomView:button];self.navigationItem.leftBarButtonItem=btnItem;}-(BOOL)gestureRecognizerShouldBegin{[selfonBack];returnNO;}-(void)onBack{UIAlertView*alertView=[[UIAlertViewTitalloc]initW@《表哥的技术博客》message:@"你知道博客地址是什么吗?"delegate:selfcancelButtonTitle:@"不知道"otherButtonTitles:@"知道",nil];[alertViewshow];}#pragmamark-UIAlertViewDelegate-(void)alertView:(UIAlertView*)alertViewclickedButtonAtIndex:(NSI整数)按钮输入dex{if(buttonIndex==0){}else{if([self.navigationItem.titleisEqualToString:@"VC6"]){NSUIntegerindex=self.navigationController.viewControllers.count-3;UIViewController*vc=[self.navigationController.viewControllersobjectAtIndex:index];[self.navigationControllerpopToViewController:vcanimated:YES];}else{[self.navigationControllerpopViewControllerAnimated:YES];}}}@end这个方案确实满足我们的需求,但是有没有更简单的方案呢?今天可能是眼睛有点困的原因吧。我在研究的时候没有意识到第四个选项。准备写这篇文章的时候,又重新了解了一下地理学的逻辑,发现还是有一个很简单的方案可以满足我的需求。方案四(靠谱,***)方案四:将UIGestureRecognizerDelegate放在公共导航类HYBNavigationController中,设置代理为导航类,但只遵循-gestureRecognizerShouldBegin:代理方法。@interfaceHYBNavigationController()@end@implementationHYBNavigationController-(void)viewDidLoad{[superviewDidLoad];self.interactivePopGestureRecognizer.delegate=self;}-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer{Swipe/BOOLok=YES默认支持返回如果([self.topViewControllerisKindOfClass:[HYBBaseViewControllerclass]]){if([self.topViewControllerrespondsToSelector:@selector(gestureRecognizerShouldBegin)]){HYBBaseViewController*vc=(HYBBaseViewController*)self.topViewController;ok=[vcgestureRecognizerShouldBegin];returnok;}@end的使用方法和第三种方案一样,是不是很简化?好像是元宵节的礼物,突然想到了这么一个方法。之前没有研究过interactivePopGestureRecognizer属性。这个属性是iOS7之后才有的,所以我不能在项目中直接使用leftBarButtonItem,除非界面不右滑返回。至此,一切都清楚了,使用leftBarButtonItem统一调用公共基类controller中的API进行设置就非常简单了,右滑返回手势也可以正常使用了~还等什么,快来试试吧!***如果你用的项目也有这样的需求,那就试试吧!作者提供了一个demo,大家可以先下载demo看看效果!经过多次测试,笔者认为这是一个可行的方案。如果您在使用中有问题,请反馈给作者。我也想知道是什么情况。当然,我也需要想办法共同进步。
