我們都知道,iOS7導航控制器默認自帶了側滑功能,當用戶在界面的左邊滑動的時候,就會有側滑功能。但是如果我們從從導航控制器的返回按鈕,就發現系統所帶的側滑返回功能無法使用。因此為了解決此問題,有以下方法實現:
方法一:導航控制器全屏滑動返回效果
當用戶在界面左邊拖動,就會觸發滑動手勢方法,并且有滑動返回功能,說明系統手勢觸發了方法,即調用了target的action方法,也就是說action方法內已經實現側滑返回。 系統自帶的滑動手勢interactivePopGestureRecognizer
// self指向的導航控制器,在導航控制器的viewDidLoad方法打印
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@",self.interactivePopGestureRecognizer);
}
打印結果知:
1.系統自帶的手勢是UIScreenEdgePanGestureRecognizer類型對象,屏幕邊緣滑動手勢
2.系統自帶手勢target是_UINavigationInteractiveTransition類型的對象
3.target調用的action方法名叫handleNavigationTransition:
全屏滑動代碼塊實現
- (void)viewDidLoad {
[super viewDidLoad];
// 獲取系統自帶滑動手勢的target對象
id target = self.interactivePopGestureRecognizer.delegate;
// 創建全屏滑動手勢,調用系統自帶滑動手勢的target的action方法
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
// 設置手勢代理,攔截手勢觸發 pan.delegate = self;
// 給導航控制器的view添加全屏滑動手勢
[self.view addGestureRecognizer:pan];
// 禁止使用系統自帶的滑動手勢
self.interactivePopGestureRecognizer.enabled = NO;
}
// 什么時候調用:每次觸發手勢之前都會詢問下代理,是否觸發。
// 作用:攔截手勢觸發
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
// 注意:只有非根控制器才有滑動返回功能,根控制器沒有。
// 判斷導航控制器是否只有一個子控制器,如果只有一個子控制器,肯定是根控制器
if (self.childViewControllers.count == 1) {
// 表示用戶在根控制器界面,就不需要觸發滑動手勢,
return NO; }
return YES;
}
導航控制器全屏滑動注意點:
- 1.禁止系統自帶滑動手勢使用。
- 2.只有導航控制器的非根控制器才需要觸發手勢,使用手勢代理,控制手勢觸發。
完成、這樣就搞定了, 親測此方法會與界面有滑動手勢的產生沖突,因此有第二種方法!
以上方法參考原文鏈接如下:
http://www.cocoachina.com/ios/20150811/12897.html?utm_source=tuicool)
方法二:實現自定義導航控制器邊緣滑動返回
方法二的實現原理和方法一一樣,只不過它還是使用的系統的邊緣手勢實現側滑返回功能。只需要在每個類里面添加如下代碼塊:
寫在.m中, 別忘了遵守 UIGestureRecognizerDelegate協議。
//當前導航控制器@property (nonatomic, strong) UIViewController *currentShowVC;
-(void)viewWillAppear:(BOOL)animated {
//設置代理
self.navigationController.interactivePopGestureRecognizer.delegate =(id)self;
//啟用系統自帶的滑動手勢
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
//判斷導航控制器是否只有一個子控制器,如果只有一個子控制器,肯定是根控制器,這里我的項目是有tabbar,所以在頁面切換之間設置是否顯示tababr。
if (self.navigationController.viewControllers.count == 1){
//將當前導航控制器置空
self.currentShowVC = Nil;
[SharedAppDelegate setTabBarHidden:NO animated:YES];
}else{ 如果不是根控制器,就設置當前導航控制器為其本身。
self.currentShowVC = self;
[SharedAppDelegate setTabBarHidden:YES animated:NO];
}
}
手勢的代理方法
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (gestureRecognizer ==
self.navigationController.interactivePopGestureRecognizer) { //當前導航控制器是根視圖控制器
//the most important
return (self.currentShowVC ==
self.navigationController.topViewController);
// 不要隱藏tabbar
[SharedAppDelegate setTabBarHidden:NO animated:NO];
}
return YES;
}
方法三:(推薦使用)
- 自定義UINavigationController
#import "ZGKNavigationViewController.h"
@interface ZGKNavigationViewController ()<UIGestureRecognizerDelegate>
@end
@implementation ZGKNavigationViewController
- (void)viewDidLoad {
[super viewDidLoad];
// self.interactivePopGestureRecognizer.delegate = nil;就是什么時候都可以滑動手勢,會有bug,無法點擊settingBtn
// 設置手勢代理
self.interactivePopGestureRecognizer.delegate = self;
// self.interactivePopGestureRecognizer.enabled = YES;
// 設置導航控制器navigationBar和tabBar的背景顏色可以解決導航欄黑色點的bug
[self.navigationBar setBackgroundImage:[UIImage imageNamed:@"navigationbarBackgroundWhite"] forBarMetrics:UIBarMetricsDefault];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/**
* 重寫push方法的目的 : 攔截所有push進來的子控制器(包括代碼和storyBoard實現的)
*
* @param viewController 剛剛push進來的子控制器
*/
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
if (self.childViewControllers.count > 0) { // 如果viewController不是最早push進來的子控制器,則不用設置返回按鈕
// 左上角
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setImage:[UIImage imageNamed:@"navigationButtonReturn"] forState:UIControlStateNormal];
[backButton setImage:[UIImage imageNamed:@"navigationButtonReturnClick"] forState:UIControlStateHighlighted];
[backButton setTitle:@"返回" forState:UIControlStateNormal];
[backButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[backButton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
[backButton sizeToFit];
// 這句代碼放在sizeToFit后面
backButton.contentEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0);
[backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
// 隱藏底部的工具條
viewController.hidesBottomBarWhenPushed = YES;
}
// 所有設置搞定后, 再push控制器(不要忘記調用父類方法)
[super pushViewController:viewController animated:animated];
}
- (void)back{
[self popViewControllerAnimated:YES];
}
//- (UIViewController *)popViewControllerAnimated:(BOOL)animated
//{
// return [super popViewControllerAnimated:NO];
//}
//
//- (NSArray<UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
//{
// return [super popToViewController:viewController animated:NO];
//}
//
//- (NSArray<UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated
//{
// return [super popToRootViewControllerAnimated:NO];
//}
#pragma mark - <UIGestureRecognizerDelegate>
/**
* 手勢識別器對象會調用這個代理方法來決定手勢是否有效
*
* @return YES : 手勢有效, NO : 手勢無效
*/
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// if (self.childViewControllers.count == 1) {
// return NO;
// }
//
// return YES;
// 手勢何時有效 : 當導航控制器的子控制器個數 > 1就有效
return self.childViewControllers.count > 1;
}
@end