iOS使用UIViewControllerAnimatedTransitioning自定义presentViewCont

时间:2021-03-13 18:32:12

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

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

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

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewCont 模态风格属性

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewCont 模态风格枚举

 

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

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

忽略我的丑字。嘿。

 

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

过程:

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

话不多说,上代码

1.自定义转场动画代理

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewCont 自定义transitioningdelegate

 

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

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewCont 自定义transitioningdelegate

 

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

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

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewCont

 

iOS使用UIViewControllerAnimatedTransitioning自定义presentViewCont 动画时长
- (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