美文网首页
自定义全屏滑动返回手势

自定义全屏滑动返回手势

作者: geekAppke | 来源:发表于2018-05-21 15:50 被阅读58次
    UIScreenEdgePanGestureRecognizer : UIPanGestureRecognizer : UIPanGestureRecognizer
    
    专门处理在屏幕边缘触发的手势类型
    edges属性叫,来设置它的触发边缘(上、下、左、右、全部)
    
    私有类,看来是专门用来做导航控制器交互动画的
    
    delegate == _UINavigationInteractiveTransition
    taget == _UINavigationInteractiveTransition
    私有类,专门来做导航控制器交互动画
    
    acrtion == handleNavigationTransition
    - UIGestureRecognizer有个叫_targets的属性,数组
      _targets[0] == (action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7faae8508ea0>)
      是UIGestureRecognizerTarget 私有类
    
    image

    最简单版,全屏返回手势

    /**
     全屏滑动返回
     利用系统 pop返回功能
     */
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 获取系统自带滑动手势的target对象
        id target = self.interactivePopGestureRecognizer.delegate;
        // 创建全屏滑动手势,调用系统自带滑动手势的target的action方法
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
        // NSSelectorFromString(@"
        // 设置手势代理,拦截手势触发
        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;
    }
    
    • 优点:简单易于理解
    • 缺点:每个控制器不能控制自己的导航栏状态,显示也有问题
      • 不能单独设置每个控制器,全屏手势是否生效

    UINavigationController+FDFullscreenPopGesture

    • 完美解决上面问题
    - (void)fd_viewWillAppear:(BOOL)animated
    {
        // 执行原始方法
        [self fd_viewWillAppear:animated];
        
        // 即将要显示时,调用block, 完成每个控制器 导航栏你的显示
        if (self.fd_willAppearInjectBlock) {
            self.fd_willAppearInjectBlock(self, animated);
        }
    }
    ---------------------------------------------------------
    
    - (void)fd_pushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.fd_fullscreenPopGestureRecognizer]) {
           
            // 添加自定义全屏手势
            [self.interactivePopGestureRecognizer.view addGestureRecognizer:self.fd_fullscreenPopGestureRecognizer];
            
            // 使用系统侧滑返回手势 target 和 处理方法
            NSArray *internalTargets = [self.interactivePopGestureRecognizer valueForKey:@"targets"];
            id internalTarget = [internalTargets.firstObject valueForKey:@"target"];
            // 私有处理方法不能用kvc 获取??
            SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");
            // 为手势设置代理
            self.fd_fullscreenPopGestureRecognizer.delegate = self.fd_popGestureRecognizerDelegate;
            // 为手势设置target-action
            [self.fd_fullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction];
            
            // 禁用系统的手势事件
            self.interactivePopGestureRecognizer.enabled = NO;
        }
        
        // 处理所有 push方法 之前都进行操作
        [self fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:viewController];
        
        // 调用原始方法 进行push, 判断已经有这个子控制器,就不会push
        if (![self.viewControllers containsObject:viewController]) {
            [self fd_pushViewController:viewController animated:animated];
        }
    }
    
    
    /**
     所有push操作,都会来到这个方法
     对导航栏外观 进行预处理
     */
    - (void)fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewController *)appearingViewController
    {
        // 导航控制器 是否允许 所有导航栏的操作
        // 为NO 各个子控制器不能单独操作
        if (!self.fd_viewControllerBasedNavigationBarAppearanceEnabled) {
            return;
        }
        
        // 创建实现一个block 包含2个参数
        // 进行处理操作
        __weak typeof(self) weakSelf = self;
        _FDViewControllerWillAppearInjectBlock block = ^(UIViewController *viewController, BOOL animated) {
            __strong typeof(weakSelf) strongSelf = weakSelf;
            if (strongSelf) {
                [strongSelf setNavigationBarHidden:viewController.fd_prefersNavigationBarHidden animated:animated];
            }
        };
        
        // 给即将push进来的控制器 赋值blcok
        // 以后传什么参数, 由它自己决定!
        appearingViewController.fd_willAppearInjectBlock = block;
        // 给即将消失是的控制器 赋值block, 就是当前控制器
        // 有的子控制器不是 push进来的, 本身就是导航控制器的 根控制器
        UIViewController *disappearingViewController = self.viewControllers.lastObject;
        if (disappearingViewController && !disappearingViewController.fd_willAppearInjectBlock) {
            disappearingViewController.fd_willAppearInjectBlock = block;
        }
    }
    
    - (_FDFullscreenPopGestureRecognizerDelegate *)fd_popGestureRecognizerDelegate
    {
        _FDFullscreenPopGestureRecognizerDelegate *delegate = objc_getAssociatedObject(self, _cmd);
        
        if (!delegate) {
            delegate = [[_FDFullscreenPopGestureRecognizerDelegate alloc] init];
            delegate.navigationController = self;
            
            objc_setAssociatedObject(self, _cmd, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
        return delegate;
    }
    
    /**
     懒加载创建 自定义全屏手势
     */
    - (UIPanGestureRecognizer *)fd_fullscreenPopGestureRecognizer
    {
        UIPanGestureRecognizer *panGestureRecognizer = objc_getAssociatedObject(self, _cmd);
        
        if (!panGestureRecognizer) {
            panGestureRecognizer = [[UIPanGestureRecognizer alloc] init];
            panGestureRecognizer.maximumNumberOfTouches = 1;
            
            objc_setAssociatedObject(self, _cmd, panGestureRecognizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
        return panGestureRecognizer;
    }
    
    image

    全屏滑动返回手势

    相关文章

      网友评论

          本文标题:自定义全屏滑动返回手势

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