自定义转场动画

好久不用的东西,复习一下,先写一下转场动画吧O(∩_∩)O

直接开始,这篇博客分三部分,第一部分记述自定义modal动画,第二部记述自定义push动画,第三部分记一下常见动画的实现.

modal动画

下面简要写一下以modal的形式实现系统的push动画

主要步骤:
新建两个view controller,记做FromVC,ToVC;
在FromVC中,实现presentViewController:animated:completion,ToVC对象设置toVC.transitioningDelegate = self;,fromVC遵守协议UIViewControllerTransitioningDelegate;
看一下UIViewControllerTransitioningDelegate, 通过文档可以看到, UIViewControllerTransitioningDelegate主要要实现前两个方法来获取present和dismiss的动画对象

1
2
3
4
5
6
7
8
9
10
// Asks your delegate for the transition animator object to use when presenting a view controller.
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
// Asks your delegate for the transition animator object to use when dismissing a view controller.
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
// Asks your delegate for the interactive animator object to use when presenting a view controller.
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator;
// Asks your delegate for the interactive animator object to use when dismissing a view controller.
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
// Asks your delegate for the custom presentation controller to use for managing the view hierarchy when presenting a view controller.
- (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0);

而动画对象需要遵守UIViewControllerAnimatedTransitioning协议,看一下这个协议需要实现的方法:第一个方法返回的是动画执行的时间,第二个方法则是用于处理动画效果;

1
2
3
4
5
// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
// synchronize with the main animation.
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
// This method can only be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

首先实现present动画,新建一个DHPresentAnimation类,继承自NSObject,并且实现UIViewControllerAnimatedTransitioning中的两个方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 动画执行的时间
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContex
{
return 0.3;
}
// 自定义动画
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
// 获取目标VC
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 获取最终要显示的VC的frame
CGRect finalRect = [transitionContext finalFrameForViewController:toVC];
// 设置目标VC的默认位置,这里定位在屏幕左侧
toVC.view.frame = CGRectOffset(finalRect, -[[UIScreen mainScreen]bounds].size.width, 0);
// 获取containerView,并将目标VC的view设置为它的子视图
[[transitionContext containerView] addSubview:toVC.view];
// 简单UIView动画,使toVC的view变换到最终要显示的位置和大小
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toVC.view.frame = finalRect;
} completion:^(BOOL finished) {
// 明确告诉上下文,结束动画
[transitionContext completeTransition:YES];
}];
}

FromVC中,实现UIViewControllerTransitioningDelegate协议方法

1
2
3
4
5
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
// 返回present自定义动画对象
return [[DHPresentAnimation alloc] init];
}

同理,实现dismiss动画,实现FromVC遵循协议中的另一个方法:
dismiss动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 1.0;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
CGRect initRect = [transitionContext initialFrameForViewController:fromVC];
CGRect finalRect = CGRectOffset(initRect, -[[UIScreen mainScreen]bounds].size.width, 0);
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toVC.view];
[containerView sendSubviewToBack:toVC.view];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromVC.view.frame = finalRect;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}

协议方法:

1
2
3
4
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return [[DHDismissAnimation alloc] init];
}

最后command + R运行.

push动画

待续

常见动画的实现

待续