zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    Linux sort -n 与 -g 排序对比
    shell中IF的用法介绍
    Firewalld 用法解析
    Centos7最小化安装后再安装图形界面
    PXE无人值守部署centos7.4操作系统
    kali之获取靶机的图片和看的url
    Kali的源得数字验证问题
    kali之Nmap (Network Mapper(网络映射器)
    kali之EtterCap学习
    Kali linux查看局域网内其他用户的输入信息
  • 原文地址:https://www.cnblogs.com/isItOk/p/5686270.html
Copyright © 2011-2022 走看看