美文网首页收藏ios
iOS —Nav全屏滑动返回详解

iOS —Nav全屏滑动返回详解

作者: 浮桥小麦 | 来源:发表于2017-04-21 11:19 被阅读209次
    一击即中.jpeg
    前言:今天好好讲解一下导航栏全屏手势返回,以前只知道拿别人的来用,现在想花点时间了解其中的原理。 今天把自己学习到的分享出来,大家一起学习进步。。。
    Pragma mark — NO.1 使用全屏返回的原因与技术背景
    1.手机屏幕大了,没有全屏返回,用户体验感下降(虽然很多人也学还不知道大多数应用都有全屏返回功能,还傻傻的去点左上角的返回键)
    2. 界面要求:
    -1 : 要求在下个push出来的控制器中隐藏掉导航栏,那么我们系统自带的左侧边缘滑动返回也没有了
    -2 : push出来的控制器左上角的返回键我们通常需要用按钮自定义,这种情况下也会覆盖掉左侧边缘滑动返回
    
    
    
    
    Pragma mark — NO.2 简单界面搭建
    1. 创建个空工程,然后在main storyboard 中给 viewController Embed in 一个navigation controller
    2.自己创建一个navigation controller ,与main storyboard 中的关联起来 
    3.创建一个nextViewController ,点击viewController  push 到 nextViewController .
    4.在nextViewController 中隐藏 这个 navigationBar 
    5.点击nextViewController 的pop按钮  pop 到 viewController
    至此最简单的项目结构就创建好了(这里我们演示这个push隐藏导航栏的情况)
    
    Pragma mark — NO.3 简要分析
    #我们在自定义的nav中来看:
    1.系统nav有这个左侧边缘返回的手势,说明其应该有一个Pan手势,并且有这个 target 和 action , 我们直接拿到这个手势加入到nav.view的手势中,看能否实现左划返回
    
    @implementation JJNavigationController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
     [self.view addGestureRecognizer:self.interactivePopGestureRecognizer];
       }
    //self.view:拿到push出来的控制器view
    //self.interactivePopGestureRecognizer :系统给我们的导航栏pop返回手势
    //运行工程,我们发现这样做是没有任何反应的
    
    2.第二种思路:拿到系统的self.interactivePopGestureRecognizer手势中的target和action。 然后我们自己给self.view创建一个Pan(滑动手势) 将 target 和 action设置为系统的
    
    
    
    Pragma mark — NO.4 利用runtime 取得系统手势的targer属性
    #对于runtime不熟悉的伙伴,可以自行了解一下
    #import "JJNavigationController.h"
    #import <objc/runtime.h>
    
    @interface JJNavigationController ()
    
    @end
    
    @implementation JJNavigationController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //1.通过运行时,打印手势中的所有属性
        unsigned int count = 0;
        //拷贝所有关于手势的属性,包含私有属性
        Ivar *ivars = class_copyIvarList([UIGestureRecognizer class], &count);
        //遍历这个属性数组,拿到每一个属性
        NSArray *ivarList = [NSArray array];
        //初始化一个count那么长的可变数组
        NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
        for (unsigned int i = 0; i < count; i++) {
            //获取成员变量名
            const char *ivarName = ivar_getName(ivars[i]);
            //获取类的成员变量的类型
            //const char *ivarType = ivar_getTypeEncoding(ivars[i]);
        [mutableList addObject:[NSString stringWithUTF8String:ivarName]];
        }
        //释放
        
        free(ivars);
        
        ivarList = [NSArray arrayWithArray:mutableList];
        
        NSLog(@"手势所有属性名--%@",ivarList);
    }
    
    #打印结果:
    Nav全屏手势返回[1773:90512] 手势所有属性名--(
        "_gestureFlags",
        "_targets",
        "_delayedTouches",
        "_delayedPresses",
        "_view",
        "_lastTouchTimestamp",
        "_state",
        "_allowedTouchTypes",
        "_initialTouchType",
        "_internalActiveTouches",
        "_forceClassifier",
        "_requiredPreviewForceState",
        "_touchForceObservable",
        "_touchForceObservableAndClassifierObservation",
        "_forceTargets",
        "_forcePressCount",
        "_beganObservable",
        "_failureRequirements",
        "_failureDependents",
        "_delegate",
        "_allowedPressTypes",
        "_gestureEnvironment"
    )
    
    Pragma mark — NO.5 通过KVC取得系统手势的action 和 target
    #通过上面的属性打印,我们可以看出@“_targets”应该是我们想要的
    @implementation JJNavigationController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"_targets"];
        NSLog(@"targets中的东西%@",targets);
    }
    #打印结果
    targets中的东西(
        "(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7f9210f0f2c0>)"
    )
    这样我们就拿到系统手势的action和target
    
    
    Pragma mark — NO.6 创建Pan手势添加target和action
    #获得系统的target 和 action
     NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"_targets"];
       // NSLog(@"targets中的东西%@",targets);
    
        id target = [targets.firstObject valueForKey:@"target"];
        SEL action = NSSelectorFromString(@"handleNavigationTransition:");
    
    #创建Pan手势
    //创建滑动手势
        UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:target action:action];
        [self.view addGestureRecognizer:panGesture];
    
    #再次运行工程,我们会发现就已经可全屏pop返回了
    
    
    • 疑问:我们在nextViewController中没有处理过任何手势相关的东西,为什么我们拖动nextViewController的view,会有拖动手势?
      • 解惑:这其中涉及到一个响应者链问题。因为我们的nextViewController的view实际上是加在它的父控件,nav.view上的。 所以我们拖动next.view会有手势。

    完整项目地址: nav全屏返回

    尾声:我将刘凡老师的语法糖也加入进去了,他将这个全屏返回实现写成了一个nav的分类。 技术点用的是runtime交换方法。 大家可以在理解了简单版的基础上学习一下。 可以作为以后面试官问你用runtime做过哪些事情的谈资(嘿嘿)!

    相关文章

      网友评论

        本文标题:iOS —Nav全屏滑动返回详解

        本文链接:https://www.haomeiwen.com/subject/wuzrzttx.html