iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画

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

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

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

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画
模态风格属性

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画
模态风格枚举

 

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

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


忽略我的丑字。嘿。

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画
自定义转场动画流程

过程:

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


话不多说,上代码

1.自定义转场动画代理

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画
自定义transitioningdelegate

 

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

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画
自定义transitioningdelegate

 

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

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

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewController动画
动画时长
- (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 = 
上一篇:《高校后勤管理移动应用系统设计》论文笔记六


下一篇:Android 7.0 以上 Charles 和 Fiddler 无法抓取 HTTPS 包的解决方式