• 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.0, 1.0, 0.0);  
    19.     viewToTransform = CATransform3DMakeRotation(-ROTATION_ANGLE, 0.0, 1.0, 0.0);  
    20.     [toView.layer setAnchorPoint:CGPointMake(0, 0.5)];  
    21.     [fromView.layer setAnchorPoint:CGPointMake(1, 0.5)];  
    22.       
    23. //    [generalContentView setTransform:CGAffineTransformMakeTranslation(generalContentView.frame.size.width/2.0, 0)];  
    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.0, 0)];  
    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. }  
    -(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5f;
    }
    
    -(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
    
        //Create the differents 3D animations
        CATransform3D viewFromTransform;
        CATransform3D viewToTransform;
        
        UIView *generalContentView = [transitionContext containerView];
        UIView *fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view;
        UIView *toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
    
        
        viewFromTransform = CATransform3DMakeRotation(ROTATION_ANGLE, 0.0, 1.0, 0.0);
        viewToTransform = CATransform3DMakeRotation(-ROTATION_ANGLE, 0.0, 1.0, 0.0);
        [toView.layer setAnchorPoint:CGPointMake(0, 0.5)];
        [fromView.layer setAnchorPoint:CGPointMake(1, 0.5)];
        
    //    [generalContentView setTransform:CGAffineTransformMakeTranslation(generalContentView.frame.size.width/2.0, 0)];
        
        viewFromTransform.m34 = PERSPECTIVE;
        viewToTransform.m34 = PERSPECTIVE;
        
        toView.layer.transform = viewToTransform;
        
    
        //Add the to- view
        [generalContentView addSubview:toView];
        
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            [generalContentView setTransform:CGAffineTransformMakeTranslation(-generalContentView.frame.size.width/2.0, 0)];
            
            fromView.layer.transform = viewFromTransform;
            toView.layer.transform = CATransform3DIdentity;
            
        } completion:^(BOOL finished) {
            
            //Set the final position of every elements transformed
            [generalContentView setTransform:CGAffineTransformIdentity];
            fromView.layer.transform = CATransform3DIdentity;
            toView.layer.transform = CATransform3DIdentity;
            [fromView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
            [toView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
            
            
            if ([transitionContext transitionWasCancelled]) {
                [toView removeFromSuperview];
            } else {
                [fromView removeFromSuperview];
            }
            
            // inform the context of completion
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            
        }];
    }
    

    手势交互代码:

    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. }  
    -(void)wireToViewController:(UIViewController *)viewController
    {
        self.presentingVC = viewController;
        [self prepareGestureRecognizerInView:viewController.view];
    }
    
    - (void)prepareGestureRecognizerInView:(UIView*)view {
        UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
        [view addGestureRecognizer:gesture];
    }
    
    -(CGFloat)completionSpeed
    {
        return 1 - self.percentComplete;
    }
    
    - (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer {
        CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view.superview];
        switch (gestureRecognizer.state) {
            case UIGestureRecognizerStateBegan:
                // 1. Mark the interacting flag. Used when supplying it in delegate.
                self.interacting = YES;
                [self.presentingVC dismissViewControllerAnimated:YES completion:nil];
                break;
            case UIGestureRecognizerStateChanged: {
                // 2. Calculate the percentage of guesture
                CGFloat fraction = -translation.x / 300.0;
                //Limit it between 0 and 1
                fraction = fminf(fmaxf(fraction, 0.0), 1.0);
                self.shouldComplete = (fraction > 0.5);
                
                [self updateInteractiveTransition:fraction];
                break;
            }
            case UIGestureRecognizerStateEnded:
            case UIGestureRecognizerStateCancelled: {
                // 3. Gesture over. Check if the transition should happen or not
                self.interacting = NO;
                if (!self.shouldComplete || gestureRecognizer.state == UIGestureRecognizerStateCancelled) {
                    [self cancelInteractiveTransition];
                } else {
                    [self finishInteractiveTransition];
                }
                break;
            }
            default:
                break;
        }
    }
    

    根据手势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.0, 1.0, 0.0);  
    19.     viewToTransform = CATransform3DMakeRotation(-ROTATION_ANGLE, 0.0, 1.0, 0.0);  
    20.     [toView.layer setAnchorPoint:CGPointMake(0, 0.5)];  
    21.     [fromView.layer setAnchorPoint:CGPointMake(1, 0.5)];  
    22.       
    23. //    [generalContentView setTransform:CGAffineTransformMakeTranslation(generalContentView.frame.size.width/2.0, 0)];  
    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.0, 0)];  
    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. }  
    -(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5f;
    }
    
    -(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
    
        //Create the differents 3D animations
        CATransform3D viewFromTransform;
        CATransform3D viewToTransform;
        
        UIView *generalContentView = [transitionContext containerView];
        UIView *fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view;
        UIView *toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
    
        
        viewFromTransform = CATransform3DMakeRotation(ROTATION_ANGLE, 0.0, 1.0, 0.0);
        viewToTransform = CATransform3DMakeRotation(-ROTATION_ANGLE, 0.0, 1.0, 0.0);
        [toView.layer setAnchorPoint:CGPointMake(0, 0.5)];
        [fromView.layer setAnchorPoint:CGPointMake(1, 0.5)];
        
    //    [generalContentView setTransform:CGAffineTransformMakeTranslation(generalContentView.frame.size.width/2.0, 0)];
        
        viewFromTransform.m34 = PERSPECTIVE;
        viewToTransform.m34 = PERSPECTIVE;
        
        toView.layer.transform = viewToTransform;
        
    
        //Add the to- view
        [generalContentView addSubview:toView];
        
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            [generalContentView setTransform:CGAffineTransformMakeTranslation(-generalContentView.frame.size.width/2.0, 0)];
            
            fromView.layer.transform = viewFromTransform;
            toView.layer.transform = CATransform3DIdentity;
            
        } completion:^(BOOL finished) {
            
            //Set the final position of every elements transformed
            [generalContentView setTransform:CGAffineTransformIdentity];
            fromView.layer.transform = CATransform3DIdentity;
            toView.layer.transform = CATransform3DIdentity;
            [fromView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
            [toView.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
            
            
            if ([transitionContext transitionWasCancelled]) {
                [toView removeFromSuperview];
            } else {
                [fromView removeFromSuperview];
            }
            
            // inform the context of completion
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            
        }];
    }
    

    待切换的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. }  
    -(IBAction)changeViewController:(id)sender
    {
        ToViewController *vc =[[ToViewController alloc] init];
        vc.delegate = self;
        vc.transitioningDelegate = self;
        [self.interactionAnimation wireToViewController:vc];
        [self presentViewController:vc animated:YES completion:nil];
    }
    
    -(void) didClickedDismissButton:(ToViewController *)viewController
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
    {
        return self.presentAnimation;
    }
    
    -(id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
    {
        return self.cubeAnimation;
    }
    
    -(id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator
    {
        return self.interactionAnimation.interacting? self.interactionAnimation:nil;
    }
    

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

  • 相关阅读:
    C# 利用TTS实现文本转语音
    Windows10提示“没有权限使用网络资源”的解决方案
    INSPIRED启示录 读书笔记
    INSPIRED启示录 读书笔记
    phpfpm的配置
    session 的工作原理
    MySQL 事务
    Redis各种数据类型的使用场景
    JavaScript 和Ajax跨域问题
    如何做URL静态化 和页面的静态化
  • 原文地址:https://www.cnblogs.com/lovewx/p/4123837.html
Copyright © 2020-2023  润新知