iOS7之定製View Controller切換效果

原文地址:iOS7之定製View Controller切換效果

在iOS5和iOS6前,View Controller的切換主要有4種: 

  • 1. Push/Pop,NavigationViewController常乾的事兒
  • 2. Tab,TabViewController點擊
  • 3. Present Modal,調用ViewController的presentViewController:animated:completion:方法
  • 4. Add ChildViewController,調用- (void)addChildViewController:(UIViewController *)childController方法


在使用Add ChildViewController的方式時,一般使用transitionFromViewController:toViewController:…的Animation block中可以實現一些簡單的切換效果,這樣做有2大不足: 
  • 1. 代碼高度耦合,VC切換部分的代碼直接寫在container中,難以分離重用;
  • 2. 支持的切換效果比較有限,因爲其只能使用UIView動畫來切換,管理起來也略顯麻煩


於是,蘋果在iOS7中引入了一些新的API來幫助開發者更容易,更鬆耦合地定義ViewController的轉換效果。 

知識點 


用法 
從上面的知識點圖中可以看出,新的API主要提供了2種VC切換的方式,一種是動畫式切換,即定義一種從一個VC到另一個VC的動畫效果,切換的時候自動播放,第二種是交互式切換,這種方式同樣需要定義動畫效果,只是這個動畫效果會根據跟隨交互式手勢來切換VC並同時播放動畫效果。 這兩種方式的用法略有不同。 

動畫式切換 
  • 首先定義一個動畫類實現接口UIViewControllerAnimatedTransitioning, 實現接口的2個方法,一個是動畫效果的時間,一個是動畫效果(- (void)animateTransition:(id )transitionContext ),實現動畫效果時可以從參數transitionContext中獲取到切換時的上下文信息,比方說從哪個VC切換到哪個VC等。
  • 在需切換的VC中實現UIViewControllerTransitioningDelegate,並實現animationController*方法,返回一個步驟1定義的動畫變量。
  • 調用展現VC切換方法,presentViewController等。


交互式切換 
  • 定義一個類實現接口UIViewControllerInteractiveTransitioning,iOS7提供了一個默認的基於百分比的動畫實現UIPercentDrivenInteractiveTransition,大家不想太麻煩可以直接擴展這個類。該類需要綁定需要實現手勢控制的VC,同時把手勢操作添加到該VC上,然後在處理手勢動作的時候,調用接口中的方法去更新當前的動畫進度。
  • 定以切換時的動畫效果類。和動畫式切換的方式一致
  • 在需切換的VC中實現UIViewControllerTransitioningDelegate,實現interactiveController方法,返回步驟1定義的類,實現animationController方法返回步驟2定義的動畫效果。


實戰 
下圖是我實現的一個VC切換的效果圖,(注:App圖片是網上隨便找的,不代表個人喜好:) 
 

實現代碼: 
VC跳入動畫的代碼: 
Object-c代碼  收藏代碼
  1. -(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext  
  2. {  
  3.     return 0.5f;  
  4. }  
  5.   
  6. -(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext  
  7. {  
  8.   
  9.     //Create the differents 3D animations  
  10.     CATransform3D viewFromTransform;  
  11.     CATransform3D viewToTransform;  
  12.       
  13.     UIView *generalContentView = [transitionContext containerView];  
  14.     UIView *fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view;  
  15.     UIView *toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;  
  16.   
  17.       
  18.     viewFromTransform = CATransform3DMakeRotation(ROTATION_ANGLE, 0.01.00.0);  
  19.     viewToTransform = CATransform3DMakeRotation(-ROTATION_ANGLE, 0.01.00.0);  
  20.     [toView.layer setAnchorPoint:CGPointMake(00.5)];  
  21.     [fromView.layer setAnchorPoint:CGPointMake(10.5)];  
  22.       
  23. //    [generalContentView setTransform:CGAffineTransformMakeTranslation(generalContentView.frame.size.width/2.00)];  
  24.       
  25.     viewFromTransform.m34 = PERSPECTIVE;  
  26.     viewToTransform.m34 = PERSPECTIVE;  
  27.       
  28.     toView.layer.transform = viewToTransform;  
  29.       
  30.   
  31.     //Add the to- view  
  32.     [generalContentView addSubview:toView];  
  33.       
  34.     [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{  
  35.         [generalContentView setTransform:CGAffineTransformMakeTranslation(-generalContentView.frame.size.width/2.00)];  
  36.           
  37.         fromView.layer.transform = viewFromTransform;  
  38.         toView.layer.transform = CATransform3DIdentity;  
  39.           
  40.     } completion:^(BOOL finished) {  
  41.           
  42.         //Set the final position of every elements transformed  
  43.         [generalContentView setTransform:CGAffineTransformIdentity];  
  44.         fromView.layer.transform = CATransform3DIdentity;  
  45.         toView.layer.transform = CATransform3DIdentity;  
  46.         [fromView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];  
  47.         [toView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];  
  48.           
  49.           
  50.         if ([transitionContext transitionWasCancelled]) {  
  51.             [toView removeFromSuperview];  
  52.         } else {  
  53.             [fromView removeFromSuperview];  
  54.         }  
  55.           
  56.         // inform the context of completion  
  57.         [transitionContext completeTransition:![transitionContext transitionWasCancelled]];  
  58.           
  59.     }];  
  60. }  

手勢交互代碼: 
Object-c代碼  收藏代碼
  1. -(void)wireToViewController:(UIViewController *)viewController  
  2. {  
  3.     self.presentingVC = viewController;  
  4.     [self prepareGestureRecognizerInView:viewController.view];  
  5. }  
  6.   
  7. - (void)prepareGestureRecognizerInView:(UIView*)view {  
  8.     UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];  
  9.     [view addGestureRecognizer:gesture];  
  10. }  
  11.   
  12. -(CGFloat)completionSpeed  
  13. {  
  14.     return 1 - self.percentComplete;  
  15. }  
  16.   
  17. - (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer {  
  18.     CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view.superview];  
  19.     switch (gestureRecognizer.state) {  
  20.         case UIGestureRecognizerStateBegan:  
  21.             // 1. Mark the interacting flag. Used when supplying it in delegate.  
  22.             self.interacting = YES;  
  23.             [self.presentingVC dismissViewControllerAnimated:YES completion:nil];  
  24.             break;  
  25.         case UIGestureRecognizerStateChanged: {  
  26.             // 2. Calculate the percentage of guesture  
  27.             CGFloat fraction = -translation.x / 300.0;  
  28.             //Limit it between 0 and 1  
  29.             fraction = fminf(fmaxf(fraction, 0.0), 1.0);  
  30.             self.shouldComplete = (fraction > 0.5);  
  31.               
  32.             [self updateInteractiveTransition:fraction];  
  33.             break;  
  34.         }  
  35.         case UIGestureRecognizerStateEnded:  
  36.         case UIGestureRecognizerStateCancelled: {  
  37.             // 3. Gesture over. Check if the transition should happen or not  
  38.             self.interacting = NO;  
  39.             if (!self.shouldComplete || gestureRecognizer.state == UIGestureRecognizerStateCancelled) {  
  40.                 [self cancelInteractiveTransition];  
  41.             } else {  
  42.                 [self finishInteractiveTransition];  
  43.             }  
  44.             break;  
  45.         }  
  46.         default:  
  47.             break;  
  48.     }  
  49. }  

根據手勢3D切換的動畫代碼: 
Object-c代碼  收藏代碼
  1. -(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext  
  2. {  
  3.     return 0.5f;  
  4. }  
  5.   
  6. -(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext  
  7. {  
  8.   
  9.     //Create the differents 3D animations  
  10.     CATransform3D viewFromTransform;  
  11.     CATransform3D viewToTransform;  
  12.       
  13.     UIView *generalContentView = [transitionContext containerView];  
  14.     UIView *fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view;  
  15.     UIView *toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;  
  16.   
  17.       
  18.     viewFromTransform = CATransform3DMakeRotation(ROTATION_ANGLE, 0.01.00.0);  
  19.     viewToTransform = CATransform3DMakeRotation(-ROTATION_ANGLE, 0.01.00.0);  
  20.     [toView.layer setAnchorPoint:CGPointMake(00.5)];  
  21.     [fromView.layer setAnchorPoint:CGPointMake(10.5)];  
  22.       
  23. //    [generalContentView setTransform:CGAffineTransformMakeTranslation(generalContentView.frame.size.width/2.00)];  
  24.       
  25.     viewFromTransform.m34 = PERSPECTIVE;  
  26.     viewToTransform.m34 = PERSPECTIVE;  
  27.       
  28.     toView.layer.transform = viewToTransform;  
  29.       
  30.   
  31.     //Add the to- view  
  32.     [generalContentView addSubview:toView];  
  33.       
  34.     [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{  
  35.         [generalContentView setTransform:CGAffineTransformMakeTranslation(-generalContentView.frame.size.width/2.00)];  
  36.           
  37.         fromView.layer.transform = viewFromTransform;  
  38.         toView.layer.transform = CATransform3DIdentity;  
  39.           
  40.     } completion:^(BOOL finished) {  
  41.           
  42.         //Set the final position of every elements transformed  
  43.         [generalContentView setTransform:CGAffineTransformIdentity];  
  44.         fromView.layer.transform = CATransform3DIdentity;  
  45.         toView.layer.transform = CATransform3DIdentity;  
  46.         [fromView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];  
  47.         [toView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];  
  48.           
  49.           
  50.         if ([transitionContext transitionWasCancelled]) {  
  51.             [toView removeFromSuperview];  
  52.         } else {  
  53.             [fromView removeFromSuperview];  
  54.         }  
  55.           
  56.         // inform the context of completion  
  57.         [transitionContext completeTransition:![transitionContext transitionWasCancelled]];  
  58.           
  59.     }];  
  60. }  


待切換的VC的動畫效果配置代碼: 
Object-c代碼  收藏代碼
  1. -(IBAction)changeViewController:(id)sender  
  2. {  
  3.     ToViewController *vc =[[ToViewController alloc] init];  
  4.     vc.delegate = self;  
  5.     vc.transitioningDelegate = self;  
  6.     [self.interactionAnimation wireToViewController:vc];  
  7.     [self presentViewController:vc animated:YES completion:nil];  
  8. }  
  9.   
  10. -(void) didClickedDismissButton:(ToViewController *)viewController  
  11. {  
  12.     [self dismissViewControllerAnimated:YES completion:nil];  
  13. }  
  14.   
  15. - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source  
  16. {  
  17.     return self.presentAnimation;  
  18. }  
  19.   
  20. -(id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed  
  21. {  
  22.     return self.cubeAnimation;  
  23. }  
  24.   
  25. -(id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator  
  26. {  
  27.     return self.interactionAnimation.interacting? self.interactionAnimation:nil;  
  28. }  



整個示例的完整代碼已提交到Github上:https://github.com/xianlinbox/iOS7_New/tree/master/iOS7_New/VCTransitions

發佈了16 篇原創文章 · 獲贊 6 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章