• iOS开发自定义转场动画


    1、转场动画

      iOS7之后开发者可以自定义界面切换的转场动画,就是在模态弹出(present、dismiss),Navigation的(push、pop),TabBar的系统切换效果之外自定义切换动画!

      模态弹出自定义出push、pop效果,可以侧滑:

    2、实现步骤

      2.1、自定义转场动画

        1》创建自定义文件

    @interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning>

        2》实现UIViewControllerAnimatedTransitioning方法

    //设置转场时间
    - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
    //设置转场效果
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

        .m相关类说明:

    //表示转场动画上下文
    UIViewControllerContextTransitioning
    //当前控制器fromVC和目标控制器toVC
    //vc1-->present-->vc2: fromVC是vc1,toVC是vc2
    //vc2-->dismiss-->vc1: fromVC是vc2,toVC是vc1
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    //对应控制器的view视图
    UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
    UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
    
    //presentingViewController,presentedViewController
    vc1-->present-->vc2,vc1.presentedViewController 就是vc2;vc2.presentingViewController 就是vc1。
    
    //更新动画进度
    - (void)updateInteractiveTransition:(CGFloat)percentComplete;
    //转场结束
    - (void)finishInteractiveTransition;
    //转场取消
    - (void)cancelInteractiveTransition;

        自定义文件:

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    typedef NS_ENUM(NSInteger, PresentType){
        PresentTypePresent,
        PresentTypeDismiss
    };
    
    @interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning>
    
    + (instancetype)makeWithTransitionType:(PresentType)type;
    - (instancetype)initWithTransitionType:(PresentType)type;
    
    
    @end
    .h文件
    #import "CustomTransform.h"
    
    @interface CustomTransform()
    
    @property(nonatomic, assign)PresentType type;
    @property(nonatomic, strong)UIView *containerView;
    @end
    
    @implementation CustomTransform
    + (instancetype)makeWithTransitionType:(PresentType)type
    {
        return [[self alloc] initWithTransitionType:type];
    }
    
    - (instancetype)initWithTransitionType:(PresentType)type
    {
        if (self == [super init]) {
            _type = type;
        }
        return self;
    }
    
    - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext
    {
        return .5;
    }
    
    
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        switch (_type) {
            case PresentTypePresent:
                [self presentTransform:transitionContext];
                break;
            case PresentTypeDismiss:
                [self dismissTransform:transitionContext];
                break;
            default:
                break;
        }
        
    }
    
    - (void)presentTransform:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        self.containerView = [transitionContext containerView];
        
        UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
        UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
        [self.containerView addSubview:toView];
        CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC];
        CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), 0,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame));
        CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), 0, CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame));
        fromView.frame = visibleFrame;
        toView.frame = rightHiddenFrame;
        fromView.layer.masksToBounds = toView.layer.masksToBounds = YES;
        [self.containerView insertSubview:toView atIndex:0];
        [UIView animateWithDuration:.5
                         animations:^{
                             fromView.frame = leftHiddenFrame;
                             toView.frame = visibleFrame;
                         }
                         completion:^(BOOL finished) {
                             if ([transitionContext transitionWasCancelled]) {
                                 [toView removeFromSuperview];
                             }
                             [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                         }];
        
    }
    
    - (void)dismissTransform:(id<UIViewControllerContextTransitioning>)transitionContext
    {
    
        UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        self.containerView = [transitionContext containerView];
        
        UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
        UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
        [self.containerView addSubview:toView];
        CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC];
        CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), 0,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame));
        CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), 0, CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame));
        fromView.frame = visibleFrame;
        toView.frame = leftHiddenFrame;
        fromView.layer.masksToBounds = toView.layer.masksToBounds = YES;
        [UIView animateWithDuration:.5
                         animations:^{
                             fromView.frame = rightHiddenFrame;
                             toView.frame = visibleFrame;
                         }
                         completion:^(BOOL finished) {
                             if ([transitionContext transitionWasCancelled]) {
                                 [toView removeFromSuperview];
                             }
                             [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                         }];
    }
    
    @end
    .m文件

      2.2、自定义交互手势

        1》创建自定义文件

    @interface CustonInteractive : UIPercentDrivenInteractiveTransition

        因为UIPercentDrivenInteractiveTransition : NSObject <UIViewControllerInteractiveTransitioning>,所以自定义时继承遵循UIViewControllerInteractiveTransitioning协议的UIPercentDrivenInteractiveTransition子类!

        2》相关文件:

    #import <UIKit/UIKit.h>
    
    @interface CustonInteractive : UIPercentDrivenInteractiveTransition
    
    @property (nonatomic, assign) BOOL interacting;
    
    - (void)wireToViewController:(UIViewController*)viewController;
    
    @end
    .h
    #import "CustonInteractive.h"
    
    
    @interface CustonInteractive()
    @property (nonatomic, strong) UIViewController *presentingVC;
    
    @end
    
    @implementation CustonInteractive
    -(void)wireToViewController:(UIViewController *)viewController
    {
        self.presentingVC = viewController;
        [self prepareGestureRecognizerInView:viewController.view];
    }
    
    - (void)prepareGestureRecognizerInView:(UIView*)view {
        UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
        [view addGestureRecognizer:gesture];
    }
    - (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer {
        CGFloat progress = [gestureRecognizer translationInView:gestureRecognizer.view.superview].x / (self.presentingVC.view.bounds.size.width * 1.0);
        progress = MIN(1.0, MAX(0.0, progress));//把这个百分比限制在0~1之间
        NSLog(@"===%lf",progress);
        if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
            self.interacting = YES;
            [self.presentingVC dismissViewControllerAnimated:YES completion:nil];
        }
        else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){
            if (self.interacting) {
                [self updateInteractiveTransition:progress];
            }
        }else if (gestureRecognizer.state == UIGestureRecognizerStateCancelled||gestureRecognizer.state==UIGestureRecognizerStateEnded){
            if (self.interacting) {
                if (progress>0.5) {
                    [self finishInteractiveTransition];
                }else{
                    [self cancelInteractiveTransition];
                }
                self.interacting = NO;
            }
        }
    }
    
    @end
    .m

      2.3、使用自定义转场动画

        1》设置代理(以模态弹出为例)设置目标控制器的 transitioningDelegate

    - (IBAction)present:(id)sender {
        PresentedViewController *vc = [[PresentedViewController alloc] init];
        vc.transitioningDelegate = self;
        [_transitionController wireToViewController:vc];
        [self presentViewController:vc animated:YES completion:nil];
    }

         附加:Navigation和TabBar代理设置(self.delegate = self)

        2》实现UIViewControllerTransitioningDelegate代理方法

    1 //设置弹出时动画协议
    2 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
    3 //设置消失时动画协议
    4 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
    5 //设置消失时手势协议
    6 - (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;

        vc1的.m文件:

     1 #import "PresentingViewController.h"
     2 #import "CustomTransform.h"
     3 #import "CustonInteractive.h"
     4 #import "PresentedViewController.h"
     5 
     6 
     7 #import "SecondTransform.h"
     8 #import "SecondInteractive.h"
     9 @interface PresentingViewController ()<UIViewControllerTransitioningDelegate,UINavigationControllerDelegate,UITabBarControllerDelegate>{
    10     SecondTransform *_presentAnimation;
    11     SecondInteractive *_transitionController;
    12 }
    13 
    14 @end
    15 
    16 @implementation PresentingViewController
    17 
    18 - (void)viewDidLoad {
    19     [super viewDidLoad];
    20     _presentAnimation = [SecondTransform new];
    21     _transitionController = [SecondInteractive new];
    22     // Do any additional setup after loading the view from its nib.
    23 }
    24 - (IBAction)present:(id)sender {
    25     PresentedViewController *vc = [[PresentedViewController alloc] init];
    26     vc.transitioningDelegate = self;
    27     [_transitionController wireToViewController:vc];
    28     [self presentViewController:vc animated:YES completion:nil];
    29 }
    30 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
    31 {
    32     return _presentAnimation;
    33 }
    34 
    35 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
    36 {
    37     return [SecondTransform makeWithTransitionType:PresentTransformAnimationTypeDismissed];
    38 }
    39 
    40 -(id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
    41     return _transitionController.isInterraction ? _transitionController : nil;
    42 }
    43 @end
    .m

         Navigation和TabBar的代理方法:

    #pragma mark---UINavigationControllerDelegate
    /*
    - (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                                       interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);
    
    - (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                                animationControllerForOperation:(UINavigationControllerOperation)operation
                                                             fromViewController:(UIViewController *)fromVC
                                                               toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);
    */
    
    #pragma mark-UITabBarControllerDelegate
    /*
    - (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController
                                   interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController NS_AVAILABLE_IOS(7_0);
    
    - (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
                         animationControllerForTransitionFromViewController:(UIViewController *)fromVC
                                                           toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);
    */
    Navigation和TabBar的delegate
  • 相关阅读:
    Maven仓库是什么
    Maven的工程类型有哪些?
    什么是Maven?
    MyBatis 与 Hibernate 有哪些不同?
    MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?
    使用过Redis做异步队列么,你是怎么用的?
    我们怎样才能在动作类中获得Servlet API请求,响应,HttpSession等对象?
    forward 和redirect的区别 ?
    你所知道的微服务技术栈有哪些?请列举一二
    SpringMVC流程?
  • 原文地址:https://www.cnblogs.com/xianfeng-zhang/p/8857040.html
Copyright © 2020-2023  润新知