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的动画效果。

转场代理使用

猜你喜欢

转载自www.cnblogs.com/frounk/p/12186600.html
今日推荐