iOS中如果不自定義UINavigationBar,通過手勢向右滑是可以實現返回的,這時左邊的標題文字提示的是上一個ViewController的標題,如果需要把文字改為簡約風格,例如弄過箭頭返回啥的,那么你需要自定義UINavigationBar,但當你自定義navigationBar后,這個功能就會自動失效。
屏蔽右滑返回功能代碼:
- if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
- self.navigationController.interactivePopGestureRecognizer.enabled = NO;
- }
開啟滑動返回功能代碼:
- - (void)viewWillAppear:(BOOL)animated{
- [super viewWillAppear:animated];
- // 右滑返回
- if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
- self.navigationController.interactivePopGestureRecognizer.delegate = nil;
- }
- }
注意各種坑:
"在一級視圖中,iOS樣式返回的手勢滑動一下,然后進入二級視圖,發現畫面卡住了,按Home鍵轉入后台,再返回應用,發現並沒有Crash掉,而是直接跳到了二級視圖里,運行正常了,大家知道push和pop的原理是用進棧出棧完成的,可能因為在一級視圖中滑動那一下,影響了視圖在棧中的位置。 "
------有人提到通過以下方法處理:“一級視圖中一定要加入self.navigationController.interactivePopGestureRecognizer.enabled = NO;,先把iOS7手勢返回屏蔽掉,到二級視圖再用self.navigationController.interactivePopGestureRecognizer.enabled = YES打開”
自己寫了個demo試運行,發現self.navigationController.interactivePopGestureRecognizer.enabled 不能動態設置更改狀態。因此該方法不可行。
解決方法:
- - (void)viewDidAppear:(BOOL)animated
- {
- __weak typeof(self) weakSelf = self;
- self.navigationController.interactivePopGestureRecognizer.delegate = weakSelf;
- }
實現手勢協議:
- #pragma mark - UIGestureRecognizerDelegate
- - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer{
- //判斷是否為rootViewController
- if (self.navigationController && self.navigationController.viewControllers.count == 1) {
- return NO;
- }
- return YES;
- }
但問題又來了,如果是一個顯示成功/失敗結果頁,滑動返回不大符合正常思維,因為需要選擇性屏蔽處理。
終極解決方法:自定義全屏滑動手勢UIPanGestureRecognizer
- //
- // BasicNavigationController.m
- //
- //
- // Copyright (c) 2016年 lvxiangan520@126.com. All rights reserved.
- //
- #import "BasicNavigationController.h"
- #import "BaseResultViewController.h"
- @interface BasicNavigationController() <UIGestureRecognizerDelegate>
- @end
- @implementation BasicNavigationController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : WhiteColor}];
- // 獲取系統自帶滑動手勢的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;
- }
- - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
- {
- [viewController.navigationItem.backBarButtonItem setTitleTextAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:Scale_Size_Smaller()]} forState:UIControlStateNormal];
- if (self.childViewControllers.count > 0) {
- viewController.hidesBottomBarWhenPushed = YES;
- }
- [super pushViewController:viewController animated:YES];
- }
- - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
- {
- // 注意:只有非根控制器才有滑動返回功能,根控制器沒有。
- // 判斷導航控制器是否只有一個子控制器,如果只有一個子控制器,肯定是根控制器
- if (self.childViewControllers.count == 1) {
- // 表示用戶在根控制器界面,就不需要觸發滑動手勢,
- return NO;
- }
- // 當前頁面是顯示結果頁,不響應滑動手勢
- UIViewController *vc = [self.childViewControllers lastObject];
- if ([vc isKindOfClass:[BaseResultViewController class]]) {
- return NO;
- }
- return YES;
- }
- @end
===========================實現app側滑返回的方案二=================================
在需要開啟側滑返回的viewdidload里面寫上 self.navigationController.interactivePopGestureRecognizer.delegate = nil;
或者干脆在 整個app的基類控制器里寫上這句。
在每個navi的rootviewcontroller里面寫上如下,這兩個方法里的東西,是解決在navi根控制器側滑的時候 出現的視覺bug
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
}
至於,在業務邏輯上不可逆的成功或者失敗的結果(比如點擊返回要跳轉首頁,而不是單純的pop當前頁)頁側滑會返回上一頁的問題的解決方案如下:
在成功的結果頁面,把導航的控制器數組里面的不需要的控制器移除即可。
比如從 a-PUSH-b-PUSH-c-PUSH-d(成功頁面, 點擊返回和側滑返回都需要返回到a,不能返回b和c)
NSMutableArray *marr = [[NSMutableArray alloc]initWithArray:self.navigationController.viewControllers];
for (int i=0; i<marr.count-1; i++) {
UIViewController * VC = marr[i];
if ([VC isKindOfClass:[B class]]) {
[marr removeObject:VC];
}
}
for (int i=0; i<marr.count-1; i++) {
UIViewController * VC = marr[i];
if ([VC isKindOfClass:[c class]]) {
[marr removeObject:VC];
}
}
self.navigationController.viewControllers = marr;
大家是通過方案一 還是 方案二 解決的,可以留言告訴我。
=======================================================
擴展:系統自帶的向右滑動手勢返回上一個界面,ios7--手勢
當從控制器A push到控制器B,我們返回控制器A,除了使用按鈕返回
[self.navigationController pushViewController:Vc animated:YES];
還可以使用ios7出來的向右滑動,返回控制器A
文檔中是這樣定義的:
@property(nullable, nonatomic, weak) id<UINavigationControllerDelegate> delegate;
@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;
----------------------------------------------------------------------
我們在控制器B中的viewDidLoad中
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES; // 手勢有效設置為YES 無效為NO
self.navigationController.interactivePopGestureRecognizer.delegate = self; // 手勢的代理設置為self
}
但是當回到控制器A中時,再想push到控制器B,就會出現卡屏,不會動的現象,因為rootView也會有向右滑動返回的問題
要解決這個問題,我們只需在控制器A的viewDidAppear中設置,interactivePopGestureRecognizer為NO:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
}
這樣即可以保證再B中向右滑返回A動后再次pushB時不會卡在A界面。
推薦大家個朋友開的淘寶小店店, 歡迎光臨