美文网首页
iOS 全屏手势返回

iOS 全屏手势返回

作者: Dolway | 来源:发表于2020-04-27 11:42 被阅读0次

    方案一:

    //  UINavigationController+FUFNavigation.h
    //  ShellApp
    //
    //  Created by dolway on 2020/4/24.
    //  Copyright © 2020 bri. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface UINavigationController (FUFNavigation)
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    
    //
    //  UINavigationController+FUFNavigation.m
    //  ShellApp
    //
    //  Created by dolway on 2020/4/24.
    //  Copyright © 2020 bri. All rights reserved.
    //
    
    #import "UINavigationController+FUFNavigation.h"
    
    @implementation UINavigationController (FUFNavigation)
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        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];
         
    }
    @end
    
    

    方案二:

    //
    //  Nav.h
    //  CustomPopAnimation
    //
    //  Created by Jazys on 15/3/30.
    //  Copyright (c) 2015年 Jazys. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface Nav : UINavigationController
    
    @end
    
    
    //
    //  Nav.m
    //  CustomPopAnimation
    //
    //  Created by Jazys on 15/3/30.
    //  Copyright (c) 2015年 Jazys. All rights reserved.
    //
    
    #import "Nav.h"
    #import "NavigationInteractiveTransition.h"
    
    @interface Nav () <UIGestureRecognizerDelegate>
    @property (nonatomic, weak) UIPanGestureRecognizer *popRecognizer;
    
    @property (nonatomic, strong) NavigationInteractiveTransition *navT;
    @end
    
    @implementation Nav
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        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];
    #endif
    }
    
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
        /**
         *  这里有两个条件不允许手势执行,1、当前控制器为根控制器;2、如果这个push、pop动画正在执行(私有属性)
         */
        return self.viewControllers.count != 1 && ![[self valueForKey:@"_isTransitioning"] boolValue];
    }
    
    @end
    
    //
    //  NavigationInteractiveTransition.h
    //  UIScreenEdgePanGestureRecognizer
    //
    //  Created by Jazys on 15/3/30.
    //  Copyright (c) 2015年 Jazys. All rights reserved.
    //  专门处理交互对象
    
    #import <UIKit/UIKit.h>
    
    @class UIViewController, UIPercentDrivenInteractiveTransition;
    @interface NavigationInteractiveTransition : NSObject <UINavigationControllerDelegate>
    - (instancetype)initWithViewController:(UIViewController *)vc;
    - (void)handleControllerPop:(UIPanGestureRecognizer *)recognizer;
    - (UIPercentDrivenInteractiveTransition *)interactivePopTransition;
    @end
    
    //
    //  NavigationInteractiveTransition.m
    //  UIScreenEdgePanGestureRecognizer
    //
    //  Created by Jazys on 15/3/30.
    //  Copyright (c) 2015年 Jazys. All rights reserved.
    //
    
    #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.h
    //  UIScreenEdgePanGestureRecognizer
    //
    //  Created by Jazys on 15/3/25.
    //  Copyright (c) 2015年 Jazys. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    @interface PopAnimation : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    //
    //  popAnimation.m
    //  UIScreenEdgePanGestureRecognizer
    //
    //  Created by Jazys on 15/3/25.
    //  Copyright (c) 2015年 Jazys. All rights reserved.
    //
    
    #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
    

    相关文章

      网友评论

          本文标题:iOS 全屏手势返回

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