美文网首页好东西小知识点
iOS侧滑pop返回的第三方整理研究

iOS侧滑pop返回的第三方整理研究

作者: 独孤流 | 来源:发表于2017-08-22 17:10 被阅读937次

    下一篇相关文章:UINavigationBar手势侧滑、隐藏bar、UIScrollView侧滑返回研究二

    前言

    iOS开发中都会遇到的一个问题,就是在iOS7以后苹果自动添加了侧滑pop返回手势,但一般APP由于设计的需要,会修改苹果的backBarButtonItem或是leftBarButtonItem,但只要修改这个就会导致苹果定义的这个侧滑pop返回的手势失效,于是就有了以下多种八仙过海各显神通的解决方式

    • 方案一

    作者:J_雨
    demo:TestPopGestureSolution1
    介绍文章: iOS利用Runtime自定义控制器POP手势动画

    1. 方法一:
      这篇文章介绍了2种方法,方法一是利用苹果推荐的做法,就是重写UINavigationController的两个代理方法,navigationController:animationControllerForOperation:fromViewController:toViewController:(返回一个处理交互的类)
      navigationController:interactionControllerForAnimationController:
      同时获取UINavigationController的interactivePopGestureRecognizer,并获取这个pop手势的View,然后给这个View添加新的手势处理
        UIGestureRecognizer *gesture = self.interactivePopGestureRecognizer;
        gesture.enabled = NO;
        UIView *gestureView = gesture.view;
        
        UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
        popRecognizer.delegate = self;
        popRecognizer.maximumNumberOfTouches = 1;
        [gestureView addGestureRecognizer:popRecognizer];
        
        _navT = [[NavigationInteractiveTransition alloc] initWithViewController:self];
        [popRecognizer addTarget:_navT action:@selector(handleControllerPop:)];
    

    具体手势的处理以及UINavigationController的代理都在NavigationInteractiveTransition

    #import "NavigationInteractiveTransition.h"
    #import "PopAnimation.h"
    
    @interface NavigationInteractiveTransition ()
    @property (nonatomic, weak) UINavigationController *vc;
    @property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactivePopTransition;
    @end
    
    @implementation NavigationInteractiveTransition
    
    - (instancetype)initWithViewController:(UIViewController *)vc
    {
        self = [super init];
        if (self) {
            self.vc = (UINavigationController *)vc;
            self.vc.delegate = self;
        }
        return self;
    }
    
    /**
     *  我们把用户的每次Pan手势操作作为一次pop动画的执行
     */
    - (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer {
        /**
         *  interactivePopTransition就是我们说的方法2返回的对象,我们需要更新它的进度来控制Pop动画的流程,我们用手指在视图中的位置与视图宽度比例作为它的进度。
         */
        CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width;
        /**
         *  稳定进度区间,让它在0.0(未完成)~1.0(已完成)之间
         */
        progress = MIN(1.0, MAX(0.0, progress));
        if (recognizer.state == UIGestureRecognizerStateBegan) {
            /**
             *  手势开始,新建一个监控对象
             */
            self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
            /**
             *  告诉控制器开始执行pop的动画
             */
            [self.vc popViewControllerAnimated:YES];
        }
        else if (recognizer.state == UIGestureRecognizerStateChanged) {
            
            /**
             *  更新手势的完成进度
             */
            [self.interactivePopTransition updateInteractiveTransition:progress];
        }
        else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
            
            /**
             *  手势结束时如果进度大于一半,那么就完成pop操作,否则重新来过。
             */
            if (progress > 0.5) {
                [self.interactivePopTransition finishInteractiveTransition];
            }
            else {
                [self.interactivePopTransition cancelInteractiveTransition];
            }
    
            self.interactivePopTransition = nil;
        }
        
    }
    
    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                      animationControllerForOperation:(UINavigationControllerOperation)operation
                                                   fromViewController:(UIViewController *)fromVC
                                                     toViewController:(UIViewController *)toVC {
        /**
         *  方法1中判断如果当前执行的是Pop操作,就返回我们自定义的Pop动画对象。
         */
        if (operation == UINavigationControllerOperationPop)
            return [[PopAnimation alloc] init];
    
        return nil;
    }
    
    - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                             interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
    
        /**
         *  方法2会传给你当前的动画对象animationController,判断如果是我们自定义的Pop动画对象,那么就返回interactivePopTransition来监控动画完成度。
         */
        if ([animationController isKindOfClass:[PopAnimation class]])
            return self.interactivePopTransition;
    
        return nil;
    }
    @end
    

    具体的动画在PopAnimation,改类实现UIViewControllerAnimatedTransitioning这个转场动画协议
    具体实现

    #import "PopAnimation.h"
    
    @interface PopAnimation ()
    @property (nonatomic, strong) id <UIViewControllerContextTransitioning> transitionContext;
    @end
    
    @implementation PopAnimation
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
        //这个方法返回动画执行的时间
        return 0.25;
    }
    
    /**
     *  transitionContext你可以看作是一个工具,用来获取一系列动画执行相关的对象,并且通知系统动画是否完成等功能。
     */
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
        /**
         *  获取动画来自的那个控制器
         */
        UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        /**
         *  获取转场到的那个控制器
         */
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        
        /**
         *  转场动画是两个控制器视图时间的动画,需要一个containerView来作为一个“舞台”,让动画执行。
         */
        UIView *containerView = [transitionContext containerView];
        [containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
        
        NSTimeInterval duration = [self transitionDuration:transitionContext];
    
        /**
         *  执行动画,我们让fromVC的视图移动到屏幕最右侧
         */
        [UIView animateWithDuration:duration animations:^{
            fromViewController.view.transform = CGAffineTransformMakeTranslation([UIScreen mainScreen].bounds.size.width, 0);
        }completion:^(BOOL finished) {
            /**
             *  当你的动画执行完成,这个方法必须要调用,否则系统会认为你的其余任何操作都在动画执行过程中。
             */
            [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
        }];
        
    //    _transitionContext = transitionContext;
        //----------------pop动画一-------------------------//
        /*
        [UIView beginAnimations:@"View Flip" context:nil];
        [UIView setAnimationDuration:duration];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:containerView cache:YES];
        [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:)];
        [UIView commitAnimations];//提交UIView动画
        [containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
        */
        //----------------pop动画二-------------------------//
        /*
        CATransition *tr = [CATransition animation];
        tr.type = @"cube";
        tr.subtype = @"fromLeft";
        tr.duration = duration;
        tr.removedOnCompletion = NO;
        tr.fillMode = kCAFillModeForwards;
        tr.delegate = self;
        [containerView.layer addAnimation:tr forKey:nil];
        [containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
         */
    }
    
    - (void)animationDidStop:(CATransition *)anim finished:(BOOL)flag {
        [_transitionContext completeTransition:!_transitionContext.transitionWasCancelled];
    }
    @end
    
    1. 方法二
      使用Runtime+KVC的方式,给UINavigationController的interactivePopGestureRecognizer.view添加一个自定义的手势,然后处理这个手势的target-action使用系统本身处理的target-action
        UIGestureRecognizer *gesture = self.interactivePopGestureRecognizer;
        gesture.enabled = NO;
        UIView *gestureView = gesture.view;
        
        UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
        popRecognizer.delegate = self;
        popRecognizer.maximumNumberOfTouches = 1;
        [gestureView addGestureRecognizer:popRecognizer];
    /**
         *  获取系统手势的target数组
         */
        NSMutableArray *_targets = [gesture valueForKey:@"_targets"];
        /**
         *  获取它的唯一对象,我们知道它是一个叫UIGestureRecognizerTarget的私有类,它有一个属性叫_target
         */
        id gestureRecognizerTarget = [_targets firstObject];
        /**
         *  获取_target:_UINavigationInteractiveTransition,它有一个方法叫handleNavigationTransition:
         */
        id navigationInteractiveTransition = [gestureRecognizerTarget valueForKey:@"_target"];
        /**
         *  通过前面的打印,我们从控制台获取出来它的方法签名。
         */
        SEL handleTransition = NSSelectorFromString(@"handleNavigationTransition:");
        /**
         *  创建一个与系统一模一样的手势,我们只把它的类改为UIPanGestureRecognizer
         */
        [popRecognizer addTarget:navigationInteractiveTransition action:handleTransition];
    

    以上两种方式在使用时都需要处理已经是pop到rootViewController后的情况,以及要处理正在侧滑动画时不能继续走这个侧滑转场动画,所以作者添加了对gesture代理的判断

    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
        /**
         *  这里有两个条件不允许手势执行,1、当前控制器为根控制器;2、如果这个push、pop动画正在执行(私有属性)
         */
        return self.viewControllers.count != 1 && ![[self valueForKey:@"_isTransitioning"] boolValue];
    }
    

    作者demo链接:CustomPopAnimation

    • 方案二

    作者:forkingdog
    demo:TestPopGestureSolution2
    文章说明:一个丝滑的全屏滑动返回手势
    GitHub地址:FDFullscreenPopGesture
    这个库作者说是参考了上面列的J_雨的那个Runtime+KVC的天才思路,具体的实现做了更多的封装与优化,主要使用分类category的方法无侵入的给所有UINavigationController添加侧滑返回的手势,这样方便无论使用了自动有nav还是系统nav都能不做任何修改就能集成到项目中
    具体的代码
    分类UINavigationController(FDFullscreenPopGesture)处理侧滑返回
    分类UIViewController (FDFullscreenPopGesture)添加几个属性,让UIViewController可以方便调用一些基本的操作
    fd_interactivePopDisabled是否禁用侧滑返回手势
    fd_prefersNavigationBarHidden隐藏或显示导航栏
    fd_interactivePopMaxAllowedInitialDistanceToLeftEdge左侧最大响应侧滑的位置
    具体实现:在load方法里使用Runtime修改UINavigationController的pushViewController:animated:方法,用fd_pushViewController:animated:实现push,如果当前NavigationController没有添加自定义的手势,则添加手势,同时给viewController添加viewWillAppear:viewWillAppear:添加执行block

    - (void)fd_pushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.fd_fullscreenPopGestureRecognizer]) {
            
            // Add our own gesture recognizer to where the onboard screen edge pan gesture recognizer is attached to.
            [self.interactivePopGestureRecognizer.view addGestureRecognizer:self.fd_fullscreenPopGestureRecognizer];
            
            // Forward the gesture events to the private handler of the onboard gesture recognizer.
            NSArray *internalTargets = [self.interactivePopGestureRecognizer valueForKey:@"targets"];
            id internalTarget = [internalTargets.firstObject valueForKey:@"target"];
            SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");
            self.fd_fullscreenPopGestureRecognizer.delegate = self.fd_popGestureRecognizerDelegate;
            [self.fd_fullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction];
            
            // Disable the onboard gesture recognizer.
            self.interactivePopGestureRecognizer.enabled = NO;
        }
        
        // Handle perferred navigation bar appearance.
        [self fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:viewController];
        
        // Forward to primary implementation.
        if (![self.viewControllers containsObject:viewController]) {
            [self fd_pushViewController:viewController animated:animated];
        }
    }
    /**
     给即将要显示的Controller添加执行viewWillAppear的block和viewWillDisappear的block
    
     @param appearingViewController 即将出现的Controller
     */
    - (void)fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewController *)appearingViewController
    {
        if (!self.fd_viewControllerBasedNavigationBarAppearanceEnabled) {
            return;
        }
        
        __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];
            }
        };
        
        // Setup will appear inject block to appearing view controller.
        // Setup disappearing view controller as well, because not every view controller is added into
        // stack by pushing, maybe by "-setViewControllers:".
        appearingViewController.fd_willAppearInjectBlock = block;
        UIViewController *disappearingViewController = self.viewControllers.lastObject;
        if (disappearingViewController && !disappearingViewController.fd_willAppearInjectBlock) {
            disappearingViewController.fd_willAppearInjectBlock = block;
        }
    }
    /**
     自定义的处理全局侧滑返回的gesture,使用runtime的方式保存变量
     
     @return 处理返回的gesture
     */
    - (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;
    }
    
    /**
     处理侧滑的gesture的代理
    
     @return 处理侧滑手势的代理
     */
    - (_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;
    }
    
    
    
    - (BOOL)fd_viewControllerBasedNavigationBarAppearanceEnabled
    {
        NSNumber *number = objc_getAssociatedObject(self, _cmd);
        if (number) {
            return number.boolValue;
        }
        self.fd_viewControllerBasedNavigationBarAppearanceEnabled = YES;
        return YES;
    }
    
    - (void)setFd_viewControllerBasedNavigationBarAppearanceEnabled:(BOOL)enabled
    {
        SEL key = @selector(fd_viewControllerBasedNavigationBarAppearanceEnabled);
        objc_setAssociatedObject(self, key, @(enabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    

    同时为了适配ViewController里本身有UIScrollView可以左右滚动的情形,避免滚动scrollView的手势与侧滑返回的手势冲突,可以在UIScrollView里重写方法判断

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
        if (self.contentOffset.x <= 0) {
            if ([otherGestureRecognizer.delegate isKindOfClass:NSClassFromString(@"_FDFullscreenPopGestureRecognizerDelegate")]) {
                return YES;
            }
        }
        return NO;
    }
    
    - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
     
        navigationController.interactivePopGestureRecognizer.delegate = nil;
        }
    

    为了设置让包含有scrollView的Controller也支持侧滑pop返回,直接给scrollView添加一个pan手势,处理这个手势的target-action是navgiationController.interactivePopGestureRecognizer.delegate的handleNavigationTransition方法

    @implementation UIViewController (TZPopGesture)
    
    - (void)tz_addPopGestureToView:(UIView *)view {
        if (!view) return;
        if (!self.navigationController) {
            // 在控制器转场的时候,self.navigationController可能是nil,这里用GCD和递归来处理这种情况
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self tz_addPopGestureToView:view];
            });
        } else {
            UIPanGestureRecognizer *pan = self.tz_popGestureRecognizer;
            if (![view.gestureRecognizers containsObject:pan]) {
                [view addGestureRecognizer:pan];
            }
        }
    }
    
    - (UIPanGestureRecognizer *)tz_popGestureRecognizer {
        UIPanGestureRecognizer *pan = objc_getAssociatedObject(self, _cmd);
        if (!pan) {
            // 侧滑返回手势 手势触发的时候,让target执行action
            id target = self.navigationController.tz_popDelegate;
            SEL action = NSSelectorFromString(@"handleNavigationTransition:");
            pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:action];
            pan.maximumNumberOfTouches = 1;
          // 这让nav来处理是否响应侧滑
            pan.delegate = self.navigationController;
            self.navigationController.interactivePopGestureRecognizer.enabled = NO;
            objc_setAssociatedObject(self, _cmd, pan, OBJC_ASSOCIATION_ASSIGN);
        }
        return pan;
    }
    

    同时 pan.delegate = self.navigationController;对gesture拦截处理,让nav可以对scrollView判断是响应侧滑还是正常的滑动

    - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
        if ([[self valueForKey:@"_isTransitioning"] boolValue]) {
            return NO;
        }
        if ([self.navigationController.transitionCoordinator isAnimated]) {
            return NO;
        }
        if (self.childViewControllers.count <= 1) {
            return NO;
        }
        UIViewController *vc = self.topViewController;
        if (vc.tz_interactivePopDisabled) {
            return NO;
        }
        // 侧滑手势触发位置
        CGPoint location = [gestureRecognizer locationInView:self.view];
        CGPoint offSet = [gestureRecognizer translationInView:gestureRecognizer.view];
        BOOL ret = (0 < offSet.x && location.x <= 40);
        // NSLog(@"%@ %@",NSStringFromCGPoint(location),NSStringFromCGPoint(offSet));
        return ret;
    }
    
    /// 只有当系统侧滑手势失败了,才去触发ScrollView的滑动
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
        return YES;
    }
    
    • 方案四
      在实际开发中使用过的一种方式一种简便的方式,在ViewController的viewDidLoad里添加一行代码(最好在base类里加或写一个分类统一加),这种方法简单高效但会面临一些其他问题,参考文章:navigationController侧滑
      demo:TestPopGestureSolution4
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.navigationController.interactivePopGestureRecognizer.delegate = (id)self;
       }
    

    其他非主流方案

    • 方案五
      作者:参考网上想法
      demo:TestPopGestureSolution5
      实现方式:在UINavigationController里维护一个截图的数组,同时让原生的侧滑返回失效
    - (void)loadView{
        [super loadView];
        [self initilization];
    }
    - (void)initilization{
        self.backImgs = [[NSMutableArray alloc] init];
    }
    - (void)loadBaseUI{
        //原生方法无效
        self.interactivePopGestureRecognizer.enabled = NO;
        
        //设置手势
        self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizerAction:)];
        [self.view addGestureRecognizer:self.panGestureRecognizer];
    }
    
    

    拦截push方法,让push时设置一张截图让到数组里

    #pragma mark- public method
    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
        //截图
        UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, 1.0);
        [[UIApplication sharedApplication].keyWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        [self.backImgs addObject:img];
        
        [super pushViewController:viewController animated:animated];
    }
    
    - (UIViewController *)popViewControllerAnimated:(BOOL)animated{
        [_backImgs removeLastObject];
        
        return [super popViewControllerAnimated:animated];
    }
    

    在侧滑时,对手势的移动条件及距离进行修改适配

    1. 只有在滚动的offset.x为0-40之间才处理手势
    2. 让滑动刚开始时,将上一级的Controller的截图显示出来插入superView里显示,好让有侧滑比较效果
      3、在滚动中时,将当前navigationController的View的Frame移动位置,同时设置上一级页面的截图的alpha值,让有一个渐变的效果
      4、手势结束是,判断当前手势所处位置,如果超过50,这自动无动画pop,然后删除remove背景截图,同时让navigationcontroller的frame的x为0,完整展示之前的Controller
    #pragma mark- private method
    - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
        if ([[self valueForKey:@"_isTransitioning"] boolValue]) {
            return NO;
        }
        if ([self.navigationController.transitionCoordinator isAnimated]) {
            return NO;
        }
        if (self.childViewControllers.count <= 1) {
            return NO;
        }
        //UIViewController *vc = self.topViewController;
        // 侧滑手势触发位置
        CGPoint location = [gestureRecognizer locationInView:self.view];
        CGPoint offSet = [gestureRecognizer translationInView:gestureRecognizer.view];
        BOOL ret = (0 < offSet.x && location.x <= 40);
        // NSLog(@"%@ %@",NSStringFromCGPoint(location),NSStringFromCGPoint(offSet));
        return ret;
    }
    - (void)panGestureRecognizerAction:(UIPanGestureRecognizer*)panGestureRecognizer{
        if ([self.viewControllers count] == 1) {
            return ;
        }
        
        if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {
            NSLog(@"滑动开始");
            //存放滑动开始的位置
            self.panBeginPoint = [panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow];
            //插入图片
            [self insertLastViewFromSuperView:self.view.superview];
            
        }else if(panGestureRecognizer.state == UIGestureRecognizerStateEnded){
            NSLog(@"滑动结束");
            //存放数据
            self.panEndPoint = [panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow];
            
            if ((_panEndPoint.x - _panBeginPoint.x) > 50) {
                [UIView animateWithDuration:0.3 animations:^{
                    [self moveNavigationViewWithLenght:[UIScreen mainScreen].bounds.size.width];
                } completion:^(BOOL finished) {
                    [self removeLastViewFromSuperView];
                    [self moveNavigationViewWithLenght:0];
                    [self popViewControllerAnimated:NO];
                }];
                
                
            }else{
                [UIView animateWithDuration:0.3 animations:^{
                    [self moveNavigationViewWithLenght:0];
                }];
            }
        }else{
            //添加移动效果
            CGFloat panLength = ([panGestureRecognizer locationInView:[UIApplication sharedApplication].keyWindow].x - _panBeginPoint.x);
            if (panLength > 0) {
                [self moveNavigationViewWithLenght:panLength];
            }
        }
        
    }
    
    /**
     *  移动视图界面
     *
     *  @param lenght 移动的长度
     */
    - (void)moveNavigationViewWithLenght:(CGFloat)lenght{
        
        //图片位置设置
        self.view.frame = CGRectMake(lenght, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
        //图片动态阴影
        _backView.alpha = (lenght/[UIScreen mainScreen].bounds.size.width)*2/3 + 0.33;
    }
    
    /**
     *  插图上一级图片
     *
     *  @param superView 图片的superView
     */
    - (void)insertLastViewFromSuperView:(UIView *)superView{
        //插入上一级视图背景
        if (_backView == nil) {
            _backView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
            _backView.image = [_backImgs lastObject];;
        }
        [self.view.superview insertSubview:_backView belowSubview:self.view];
    }
    
    /**
     *  移除上一级图片
     */
    - (void)removeLastViewFromSuperView{
        [_backView removeFromSuperview];
        _backView = nil;
    }
    
    

    小结

    方案一和方案二使用自定义对navigationController.interactivePopGestureRecognizer.delegate进行替换处理
    方案三和方案四是继续使用系统的interactivePopGestureRecognizer.delegate
    同时方案二和方案四都处理了scrollView的侧滑返回问题,但由于方案二处理scrollView侧滑时使用继承重写,在有些使用第三方时并不很方便,这一点,方案四一句代码就处理了很方便,就整体代码而言,感觉方案四最优,但方案二还能自动处理有无导航栏的处理,方案四没有涉及这一块儿,但方案四和方案二是可以混用的,方案二+方案四感觉是挺不错的选择
    在上面列出的几种解决方案中,只有FDFullscreenPopGesture很好的处理有没有隐藏导航栏的各个页面的切换导致navigationbar闪一下的问题,但在处理scrollView相关的侧滑时使用的方式不是很优雅,而且对于一些不能重新定义一个scrollView子类的页面没法很好的适配,而TZScrollViewPopGesture则很好的处理了这个问题,但TZScrollViewPopGesture在处理导航栏是否隐藏跳转时有点儿跳转的突兀,所以这2个合起来是最好的一种处理方式。

    全部例子demo NavPOPGestureBack

    相关文章

      网友评论

        本文标题:iOS侧滑pop返回的第三方整理研究

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