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的動畫效果。

 

轉場代理使用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM