iOS 7 自定义Back按钮 与 Pop interactive gesture
1、自定义Back按钮
iOS中很多时候我们都会自定义返回按钮,也是一件easy的事,类似如下:
// 返回按钮
1 - (void)showNavBackButton 2 { 3 UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; 4 [backButton addTarget:self action:@selector(backButtonAction:) 5 forControlEvents:UIControlEventTouchUpInside]; 6 [backButton setBackgroundImage:[UIImage imageNamed:@"00_back_button"] 7 forState:UIControlStateNormal]; 8 [backButton setTitle:kLoc(@"Back") forState:UIControlStateNormal]; 9 [backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 1, 0)]; 10 backButton.titleLabel.font = kMediumFont(12); 11 backButton.frame = CGRectMake(0, 0, 51, 31); 12 self.navigationItem.leftBarButtonItem 13 = [[UIBarButtonItem alloc] initWithCustomView:backButton]; 14 }
但是,这样在iOS7下Pop interactive gesture就不好使了。
这里 Here 有一个解决方法。
但是,测试发现在栈中推入一个controller后,快速向左平滑,将会引起崩溃。
查看崩溃日志,发现如下信息:
1 |
nested pop animation can result in corrupted navigation bar |
2、解决Pop interactive gesture问题
优化的解决方案是简单的让NavigationController自己成为响应的接受者,最好用一个UINavigationController的子类。
1)在过渡的时候禁用interactivePopGestureRecognizer
2)当新的视图控制器加载完成后再启用,建议使用UINavigationController的子类操作
// 自定义NavigationController
1 @interface DCBaseNavigationController () 2 < 3 UINavigationControllerDelegate, 4 UIGestureRecognizerDelegate 5 > 6 @end 7 8 @implementation DCBaseNavigationController 9 10 - (void)dealloc 11 { 12 self.interactivePopGestureRecognizer.delegate = nil; 13 self.delegate = nil; 14 15 [super dealloc]; 16 } 17 18 #pragma mark - View lifecycle 19 20 - (void)viewDidLoad 21 { 22 [super viewDidLoad]; 23 // Do any additional setup after loading the view. 24 25 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { 26 self.interactivePopGestureRecognizer.delegate = self; 27 self.delegate = self; 28 } 29 } 30 31 - (void)didReceiveMemoryWarning 32 { 33 [super didReceiveMemoryWarning]; 34 // Dispose of any resources that can be recreated. 35 } 36 37 #pragma mark - Override 38 39 - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated 40 { 41 // Hijack the push method to disable the gesture 42 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { 43 self.interactivePopGestureRecognizer.enabled = NO; 44 } 45 46 [super pushViewController:viewController animated:animated]; 47 } 48 49 #pragma mark - UINavigationControllerDelegate 50 51 - (void)navigationController:(UINavigationController *)navigationController 52 didShowViewController:(UIViewController *)viewController 53 animated:(BOOL)animate 54 { 55 if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { 56 navigationController.interactivePopGestureRecognizer.enabled = YES; 57 } 58 } 59 60 @end
3、Pop interactive gesture冲突,造成页面假死问题
我遇到的情况是,Push/Pop页面时,没有立即得到想要的效果,页面没有显出出来,NavigationController的didShowViewController:回调方法也没有调用。
页面布局情况是这样的:视图A,有一个Pan手势;视图B是TabBarController,其ViewControllers都是NavigationController。视图B是视图A的子视图。
后来找到原因是:navigationController的interactive pop手势与视图A的pan手势冲突。
具体原因是:rootViewController加载时,调用了didShowViewController:,设置interactivePopGestureRecognizer可用,其实我们并不需要在root的时候也触发这个手势。所以稍加优化如下:
// 优化
1 - (void)navigationController:(UINavigationController *)navigationController 2 didShowViewController:(UIViewController *)viewController 3 animated:(BOOL)animate 4 { 5 if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { 6 //if ([[navigationController.viewControllers firstObject] isEqual:viewController]) { 7 if ([navigationController.viewControllers count] == 1) { 8 // Disable the interactive pop gesture in the rootViewController of navigationController 9 navigationController.interactivePopGestureRecognizer.enabled = NO; 10 } else { 11 // Enable the interactive pop gesture 12 navigationController.interactivePopGestureRecognizer.enabled = YES; 13 } 14 } 15 }
当前显示的是root时,设置interactivePopGestureRecognizer不可用,非root时设置interactivePopGestureRecognizer可用。
参考文章:http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/