iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画

Posted frounk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画相关的知识,希望对你有一定的参考价值。

原文转自 https://www.jianshu.com/p/f4293785f1d5

UIViewControllerAnimatedTransitioning是ios系统提供的转场动画协议,遵循该协议可自定义转场动画。

系统模态一个控制器时提供了模态风格的属性

 

技术图片
模态风格属性

 

技术图片
模态风格枚举

 

分别是从底部滑入,水平翻转进入,交叉溶解以及翻页这四种风格,不受iPhone和iPad限制。

接手了一个需求是以push动画present一个控制器,系统提供的风格并不满足要求,只能动手改造转场动画。


忽略我的丑字。嘿。

 

技术图片
自定义转场动画流程

过程:

1.控制A present控制器B
2.生成遵循UIViewControllerTransitioningDelegate协议的自定义TransitioningDelegate,将 A.transitioningDelegate = 自定义transitioningdelegate
3.自定义transitioningdelegate生成自定义animatedTransitioning
4.自定义animatedTransitioning遵循UIViewControllerAnimatedTransitioning协议,实现两个必要方法动画时长及核心动画。


话不多说,上代码

1.自定义转场动画代理

技术图片
自定义transitioningdelegate

 

自定义transitioningdelegate.h 暴露了transitioningdelegate生成自定义animatedTransitioning的方法, targetEdge属性用来指定转场动画方向,可选UIRectEdgeTop,UIRectEdgeBottom,UIRectEdgeLeft,UIRectEdgeRight。用present实现push效果时使用UIRectEdgeRight。

 

技术图片
自定义transitioningdelegate

 

使用自定义transitioningdelegate生成遵循转场动画协议的自定义类

2.实现转场动画核心动画方法

技术图片

 

技术图片
动画时长
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    //源控制器
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    //目标控制器
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    // Present:
    //      fromView = The presenting view.
    //      toView   = The presented view.
    // Dismiss:
    //      fromView = The presented view.
    //      toView   = The presenting view.
    
    //容器视图
    UIView *containerView = transitionContext.containerView;
    
    UIView *fromView = nil;
    UIView *toView = nil;
    
    if ([transitionContext respondsToSelector:@selector(viewForKey:)])
    {
        //iOS8之后
        fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
        toView = [transitionContext viewForKey:UITransitionContextToViewKey];
    }
    else
    {
        //iOS7
        fromView = fromViewController.view;
        toView = toViewController.view;
    }
    
    BOOL isPresenting = (toViewController.presentingViewController == fromViewController);
    
    CGRect fromFrame = [transitionContext initialFrameForViewController:fromViewController];
    CGRect toFrame = [transitionContext finalFrameForViewController:toViewController];
    
    // Based on our configured targetEdge, derive a normalized vector that will
    // be used to offset the frame of the presented view controller.
    __block CGVector offset;
    if (self.targetEdge == UIRectEdgeTop)
        offset = CGVectorMake(0.f, 1.f);
    else if (self.targetEdge == UIRectEdgeBottom)
        offset = CGVectorMake(0.f, -1.f);
    else if (self.targetEdge == UIRectEdgeLeft)
        offset = CGVectorMake(1.f, 0.f);
    else if (self.targetEdge == UIRectEdgeRight)
        offset = CGVectorMake(-1.f, 0.f);
    else
        NSAssert(NO, @"targetEdge must be one of UIRectEdgeTop, UIRectEdgeBottom, UIRectEdgeLeft, or UIRectEdgeRight.");
    
    if (isPresenting)
    {
        // For a presentation, the toView starts off-screen and slides in.
        fromView.frame = fromFrame;
        toView.frame = CGRectOffset(toFrame, toFrame.size.width * offset.dx * -1,
                                    toFrame.size.height * offset.dy * -1);
    }
    else
    {
        fromView.frame = fromFrame;
        toView.frame = toFrame;
    }
    
    // We are responsible for adding the incoming view to the containerView
    // for the presentation.
    if (isPresenting)
    {
       [containerView addSubview:toView];
    }
    else
    {
        // -addSubview places its argument at the front of the subview stack.
        // For a dismissal animation we want the fromView to slide away,
        // revealing the toView.  Thus we must place toView under the fromView.
        [containerView insertSubview:toView belowSubview:fromView];
    }
    
    NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
    //动画
    [UIView animateWithDuration:transitionDuration animations:^{
        if (isPresenting)
        {
            toView.frame = toFrame;
        }
        else
        {
            // For a dismissal, the fromView slides off the screen.
            fromView.frame = CGRectOffset(fromFrame, fromFrame.size.width * offset.dx,
                                          fromFrame.size.height * offset.dy);
        }
        
    } completion:^(BOOL finished) {
        BOOL wasCancelled = [transitionContext transitionWasCancelled];
        
        if (wasCancelled)
        {
           [toView removeFromSuperview];
        }
        
        [transitionContext completeTransition:!wasCancelled];
    }];;
}

使用的地方生成自定义转场代理,将需要present的控制器的transitioningDelegate设置为此代理就可以看到presentViewController有了push的效果,dismiss有了pop的动画效果。

 

技术图片
转场代理使用

以上是关于iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画的主要内容,如果未能解决你的问题,请参考以下文章

[iOS] 在 ios10 中使用 imessage

使用 SmartFace.io 录制音频(Android - Ios)

iOS - 如何使用 branch.io 在 Appstore 中测试深度链接

IOS AlterView的使用(IOS8.0以前使用)

iOS归档使用

Agora.io - 如何使用 mediaPlayer 共享视频时间戳? - iOS