iOS之手勢滑動返回功能


iOS中如果不自定義UINavigationBar,通過手勢向右滑是可以實現返回的,這時左邊的標題文字提示的是上一個ViewController的標題,如果需要把文字改為簡約風格,例如弄過箭頭返回啥的,那么你需要自定義UINavigationBar,但當你自定義navigationBar后,這個功能就會自動失效。

 

屏蔽右滑返回功能代碼:

 

  1. if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {    
  2.     self.navigationController.interactivePopGestureRecognizer.enabled = NO;    
  3. }  



開啟滑動返回功能代碼:

 

  1. - (void)viewWillAppear:(BOOL)animated{  
  2.     [super viewWillAppear:animated];  
  3.       
  4.     // 右滑返回  
  5.     if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {  
  6.         self.navigationController.interactivePopGestureRecognizer.delegate = nil;  
  7.     }  
  8.   
  9. }  

 

注意各種坑:

"在一級視圖中,iOS樣式返回的手勢滑動一下,然后進入二級視圖,發現畫面卡住了,按Home鍵轉入后台,再返回應用,發現並沒有Crash掉,而是直接跳到了二級視圖里,運行正常了,大家知道push和pop的原理是用進棧出棧完成的,可能因為在一級視圖中滑動那一下,影響了視圖在棧中的位置。 "

------有人提到通過以下方法處理:“一級視圖中一定要加入self.navigationController.interactivePopGestureRecognizer.enabled = NO;,先把iOS7手勢返回屏蔽掉,到二級視圖再用self.navigationController.interactivePopGestureRecognizer.enabled = YES打開”

自己寫了個demo試運行,發現self.navigationController.interactivePopGestureRecognizer.enabled 不能動態設置更改狀態。因此該方法不可行。

 

解決方法:

 

 
  1. - (void)viewDidAppear:(BOOL)animated  
  2. {  
  3. __weak typeof(self) weakSelf = self;  
  4.  self.navigationController.interactivePopGestureRecognizer.delegate = weakSelf;  
  5. }  


實現手勢協議:

  1. #pragma mark - UIGestureRecognizerDelegate  
  2. - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer{  
  3.     //判斷是否為rootViewController  
  4.     if (self.navigationController && self.navigationController.viewControllers.count == 1) {  
  5.         return NO;  
  6.     }  
  7.     return YES;  
  8. }  


但問題又來了,如果是一個顯示成功/失敗結果頁,滑動返回不大符合正常思維,因為需要選擇性屏蔽處理。

終極解決方法:自定義全屏滑動手勢UIPanGestureRecognizer

 

 
    1. //  
    2. //  BasicNavigationController.m  
    3. //  
    4. //  
    5. //  Copyright (c) 2016年 lvxiangan520@126.com. All rights reserved.  
    6. //  
    7.   
    8. #import "BasicNavigationController.h"  
    9. #import "BaseResultViewController.h"  
    10.   
    11. @interface BasicNavigationController() <UIGestureRecognizerDelegate>  
    12.   
    13. @end  
    14.   
    15. @implementation BasicNavigationController  
    16.   
    17. - (void)viewDidLoad  
    18. {  
    19.     [super viewDidLoad];  
    20.       
    21.     [self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : WhiteColor}];  
    22.       
    23.     // 獲取系統自帶滑動手勢的target對象  
    24.     id target = self.interactivePopGestureRecognizer.delegate;  
    25.       
    26.     // 創建全屏滑動手勢,調用系統自帶滑動手勢的target的action方法  
    27.     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];  
    28.       
    29.     // 設置手勢代理,攔截手勢觸發  
    30.     pan.delegate = self;  
    31.       
    32.     // 給導航控制器的view添加全屏滑動手勢  
    33.     [self.view addGestureRecognizer:pan];  
    34.       
    35.     // 禁止使用系統自帶的滑動手勢  
    36.     self.interactivePopGestureRecognizer.enabled = NO;  
    37.       
    38. }  
    39.   
    40. - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated  
    41. {  
    42.     [viewController.navigationItem.backBarButtonItem setTitleTextAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:Scale_Size_Smaller()]} forState:UIControlStateNormal];  
    43.     if (self.childViewControllers.count > 0) {  
    44.         viewController.hidesBottomBarWhenPushed = YES;  
    45.     }  
    46.     [super pushViewController:viewController animated:YES];  
    47. }  
    48.   
    49.   
    50. - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer  
    51. {  
    52.     // 注意:只有非根控制器才有滑動返回功能,根控制器沒有。  
    53.     // 判斷導航控制器是否只有一個子控制器,如果只有一個子控制器,肯定是根控制器  
    54.     if (self.childViewControllers.count == 1) {  
    55.         // 表示用戶在根控制器界面,就不需要觸發滑動手勢,  
    56.         return NO;  
    57.     }  
    58.     // 當前頁面是顯示結果頁,不響應滑動手勢  
    59.     UIViewController *vc = [self.childViewControllers lastObject];  
    60.     if ([vc isKindOfClass:[BaseResultViewController class]]) {  
    61.         return NO;  
    62.     }  
    63.       
    64.     return YES;  
    65. }  
    66.   
    67. @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界面。

 

推薦大家個朋友開的淘寶小店店, 歡迎光臨

https://shop545764523.taobao.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM