iOS自定义 Transitions 动画总结

7,021 阅读4分钟

在iOS中,当导航控制器调用 [navigationController pushViewController:secondViewController animated:YES]时,系统会提供一个过渡的动画来提高用户体验。另外,一个控制器present(或者dismiss)另一个控制器时([self presentViewController:secondViewController animated:YES completion:NULL])系统也会提供相应的过渡动画。为了使app交互效果更加精彩,iOS为我们提供了在不同场景下自定义过渡动画以及通过手势控制过渡进度的实现方案。效果先看这个demo效果

自定义 Transitions 动画的效果由实现了UIViewControllerAnimatedTransitioning协议的实例定制; 手势控制过渡进度由实现了UIViewControllerInteractiveTransitioning协议的实例定制。在不同的Transition场景下, 我们通过不同的代理方法向系统提供自定义的遵守UIViewControllerAnimatedTransitioning协议的对象和遵守UIViewControllerInteractiveTransitioning协议的对象。 知道如何将自己定义的UIViewControllerAnimatedTransitioning对象以及UIViewControllerInteractiveTransitioning对象提供会给系统;并且知道如何实现UIViewControllerInteractiveTransitioning协议以及实现UIViewControllerInteractiveTransitioning协议, 你就可以自如的实现自己的Transition动画了。


一,自定义Transitions动画使用场景

1, 一个控制器present另一个控制器的自定义转换动画

这种场景在调用[self presentViewController:secondViewController animated:YES completion:NULL][self dismissViewControllerAnimated:YES completion:NULL];时产生。实现步骤如下:

(1) 对被present的控制器设置transitioning代理对象 secondViewController.transitioningDelegate = presentationController; presentationController是实现协议UIViewControllerTransitioningDelegate 的实例。 同时设置secondViewController . modalPresentationStyle = UIModalPresentationCustom;

(2) 代理对象要实现UIViewControllerTransitioningDelegate 协议的方法,在代理方法中返回遵守UIViewControllerAnimatedTransitioning协议和UIViewControllerInteractiveTransitioning协议的对象。

@protocol UIViewControllerTransitioningDelegate <NSObject>
@optional
//返回用于present的自定义transition动画。
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
//返回用于dismiss时的自定义transition动画。
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
//返回用于present时的可进行手势交互的transition动画。
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator;
//返回用于dismiss时的可进行手势交互的transition动画。 
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
//这个在自定义PresentationController时使用。下面的sample code有相应demo.
- (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0);
@end

2, UINavigationController 中控制器的transition

这种场景在[navigationController pushViewController:secondViewController animated:YES][self.navigationController popViewControllerAnimated:YES];下产生。实现步骤如下:

(1) 设置 导航控制器的delegate : self.navigationController.delegate = self;

(2) 实现代理方法, 在代理方法中返回实现UIViewControllerAnimatedTransitioning,和UIViewControllerInteractiveTransitioning(手势控制切换过程)协议的对象。

//返回可用于进行手势交互的transition动画。 
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);
//返回自定义过渡动画
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);

3, UITabBarController中切换控制器的transition

在默认情况下,UITabBarController切换控制器是没有过渡动画效果的。通过自定义Transitiond动画为切换控制器加上过渡效果。其实现步骤如下:

(1) 设置 UITabBarController实例的代理对象: self.tabBarController.delegate = self; 代理对象必须遵守UITabBarControllerDelegate协议。

(2) 实现代理方法如下代理方法, 在代理方法中返回遵守相应协议的对象。

- (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController NS_AVAILABLE_IOS(7_0);
	
- (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
	            animationControllerForTransitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);

二,实现协议UIViewControllerAnimatedTransitioning

- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext{
	//返回执行转换控制器的时长
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
    /**
    (1), 从transitionContext 获取执行动画需要的信息例如
         UIView *containerView = transitionContext.containerView;
         UIView *fromView;
         UIView *toView;
    
    (2),将toView 添加到containerView  中(所有的要执行的动画都需要在这里面完成)
    (3),执行动画
     [UIView animateWithDuration:transitionDuration
                     animations:^{
                         //在这里执行一些动画
                     } completion:^(BOOL finished) {
                         //动画结束后,一定要调用
                         BOOL wasCancelled = [transitionContext transitionWasCancelled];
                         [transitionContext completeTransition:!wasCancelled];
     }
                         
     */
}
}

三,实现协议 UIViewControllerInteractiveTransitioning

- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
	//在这里做些初始化的操作    
    [super startInteractiveTransition:transitionContext];
}

注意: (1) 在获取UIViewControllerAnimatedTransitioning的代理方法中,如果有返回实现UIViewControllerAnimatedTransitioning协议 的对象, 那么就使用customer transition; 如果返回nil, 就使用系统默认的效果。 (2) 在获取 UIViewControllerInteractiveTransitioning的代理方法中, 如果返回实现UIViewControllerInteractiveTransitioning协议的对象, 那么transition过程就是通过手势控制的; 如过返回nil,就直接转换。


四, 使用手势控制Transition 的大致流程

将手势识别器添加到合适的view上, 根据监听到的手势的状态做出相应操作

switch (gestureRecognizer.state)
    {
        case UIGestureRecognizerStateBegan:
            /**
             监听到手势开始,触发transition。 也就是调用下面的某个方法
             [self.navigationController pushViewController:secondViewController animated:YES];(导航控制器中, 或者pop)
             或者[self presentViewController:secondViewController animated:YES completion:NULL];(presentViewController, 或者dismiss)
             或者[tabBarController setSelectedIndex:2];(tabBarController )
             */
           
            break;
        case UIGestureRecognizerStateChanged:
            /**
             更新进度
             */
            [self updateInteractiveTransition:[self percentForGesture:gestureRecognizer]];
            break;
        case UIGestureRecognizerStateEnded:
            // Dragging has finished.
            // Complete or cancel, depending on how far we've dragged.
            //根据进度决定是finishInteractiveTransition 还是 cancelInteractiveTransition 。
            if ([self percentForGesture:gestureRecognizer] >= 0.5f)
                [self finishInteractiveTransition];
            else
                [self cancelInteractiveTransition];
            break;
        default:
            // Something happened. cancel the transition.
            [self cancelInteractiveTransition];
            break;
    }

五,Sample Code

具体代码与理论相结合往往事半功倍。推荐给大家一些比较好的Sample Code.