viewController切换动画

2017-06-14  本文已影响128人  roy_pub

抛出问题

常用的viewController(VC)切换方式有以下三种:

VC切换的时候,为了使过度更自然,系统提供了切换动画,例如Push切换会有animated属性。系统提供的动画效果,并不总是能满足我们需求,如果想要自定义切换动画该怎么处理?


问题猜测

VC 切换的时候,设置动画效果,默认执行的是系统动画,所以需要告诉程序在什么情况下执行自定义动画,而不是执行系统动画,自定义动画的触发条件是什么?
确定了自定义动画的触发条件,我们就需要执行自定义动画效果,如何写自定义动画效果?


API分析

上面绕了一圈,绕出两个问题,先看第一个,自定义动画的触发条件是什么?

在切换的时候,系统会向实现了这些接口的对象询问是否使用自定义切换效果。比如自定义Present动画,VC遵守了UIViewControllerTransitioningDelegate协议并实现了协议方法,就会执行自定义动画效果,自定义Push动画效果,遵守UINavigationControllerDelegate协议并实现协议相关方法,就会执行Push的自定义动画。

找到了自定义动画的触发条件,该如何执行执行自定义动画效果呢?
接下来隆重登场的是 UIViewControllerAnimatedTransitioning,该协议有两个方法:
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

第一个方法是动画执行周期,第二个方法是执行动画的具体内容,我们可以看一下方法二中的transitionContext,使用该属性可以获取执行动画的相关视图:
-(UIViewController *)viewControllerForKey:(NSString *)key; 获取VC
-(UIView *)containerView; 执行动画的容器
-(CGRect)initialFrameForViewController:(UIViewController *)vc; VC初始位置
-(CGRect)finalFrameForViewController:(UIViewController *)vc; VC切换后位置
-(void)completeTransition:(BOOL)didComplete;

说的比较晦涩,图片为简化流程,图一为整体思路,图二为具体动画过程。


1.png 2.png

手势交互

在使用导航Pop上一级界面的时候,可以在屏幕左侧边缘手势滑动返回。自定义动画如何进行手势操作?
系统已经为我们提供了相关的方法,UIPercentDrivenInteractiveTransition :
-(void)updateInteractiveTransition:(CGFloat)percentComplete 更新百分比
-(void)cancelInteractiveTransition
–(void)finishInteractiveTransition
VC添加手势,使用updateInteractiveTransition控制进度。


应用场景

两个场景,场景一模拟push和pop动画,场景二模拟presen和dismiss动画。不使用系统动画,使用自定义实现下图动画效果和手势操作。

3.gif
以导航的Push为例,讲解一个例子:
首先有一个从A界面跳转到B界面的Push动画,然后有一个从B界面返回A界面的Pop动画,以及返回的手势操作,系统默认的是左侧滑动返回,我们将手势改为手势操作区域为全屏。
首先写一个继承NSObject,遵守UIViewControllerAnimatedTransitioning协议的对象PushPopAnimation
设置动画执行时间为0.3
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.3f;
}```
Push动画和Pop动画:
`viewControllerForKey`可以获取相关`VC`,以及`VC`上的子视图。
`containerView`是执行动画容器,执行动画操作要在容器内进行。
有了动画容器以及动画对象,下一步就是执行动画效果,Push和Pop主要用到的主要是位移操作。


-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
BOOL isPushing = (_aniStyle == AnimationPushStyle);
if (isPushing) {
[self animationPush:transitionContext];
} else {
[self animationPop:transitionContext];
}
}
-(void)animationPush:(id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containView = [transitionContext containerView];
[containView addSubview:toVC.view];
CGRect visibleFrame = containView.frame;
CGRect rightFrame = CGRectMake(visibleFrame.size.width, visibleFrame.origin.y, visibleFrame.size.width, visibleFrame.size.height);
CGRect leftFrame = CGRectMake(-60, visibleFrame.origin.y, visibleFrame.size.width, visibleFrame.size.height);
toVC.view.frame = rightFrame;
fromVC.view.frame = visibleFrame;
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
toVC.view.frame = visibleFrame;
fromVC.view.frame = leftFrame;
} completion:^(BOOL finished) {
if ([transitionContext transitionWasCancelled]) {
[toVC.view removeFromSuperview];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}

-(void)animationPop:(id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containView = [transitionContext containerView];
[containView addSubview:toVC.view];
[containView bringSubviewToFront:fromVC.view];
CGRect visibleFrame = containView.frame;
CGRect rightFrame = CGRectMake(visibleFrame.size.width, visibleFrame.origin.y, visibleFrame.size.width, visibleFrame.size.height);
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
toVC.view.frame = visibleFrame;
fromVC.view.frame = rightFrame;
} completion:^(BOOL finished) {
if ([transitionContext transitionWasCancelled]) {
[toVC.view removeFromSuperview];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}

添加手势支持继承`UIPercentDrivenInteractiveTransition`
#### Demo地址
[Demo地址](https://github.com/royblog/YGTransitionAnimation)
上一篇 下一篇

猜你喜欢

热点阅读