iOS 7之后,苹果提供了自定义转场动画的API,我们可以自己去定义任意动画效果。本篇为笔者学习push、pop自定义转场效果的笔记,如何有任何不正确或者有指导意见的,请在评论中留下您的宝贵意见!!!
本篇只讲其中的UIViewControllerAnimatedTransitioning协议,来实现push、pop动画效果。另外的几个,后面会继续学习总结!!!
我们要实现push、pop自定义转场效果,我们必须要有一个遵守了UIViewControllerAnimatedTransitioning协议且实现其必须实现的代理方法的类。
下面我们先了解下协议:
@protocol UIViewControllerAnimatedTransitioning <NSObject>
// 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.
//
// 指定转场动画时长,必须实现,否则会Crash。
// 这个方法是为百分比驱动的交互转场和有对比动画效果的容器类控制器而定制的。
- (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;
@optional
// This is a convenience and if implemented will be invoked by the system when the transition context's completeTransition: method is invoked.
- (void)animationEnded:(BOOL) transitionCompleted;
@end
下面是具体的实现,
---------自定义push动画-----------
//转场过渡的容器view
UIView *containerView = [transitionContext containerView];
//FromVC
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIView *fromView = fromViewController.view;
[containerView addSubview:fromView];
//ToVC
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *toView = toViewController.view;
[containerView addSubview:toView];
toView.alpha = 0;
//过渡的图片
UIImageView *transitionImgView = [[UIImageView alloc] initWithImage:self.transitionImgView.image];
transitionImgView.frame = self.transitionBeforeImgFrame;
[transitionContext.containerView addSubview:transitionImgView];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
transitionImgView.frame = self.transitionAfterImgFrame;
toView.alpha = 1;
} completion:^(BOOL finished) {
[transitionImgView removeFromSuperview];
BOOL wasCancelled = [transitionContext transitionWasCancelled];
//设置transitionContext通知系统动画执行完毕
[transitionContext completeTransition:!wasCancelled];
}];
------------自定义pop动画----------
//转场过渡的容器view
UIView *containerView = [transitionContext containerView];
//ToVC
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *toView = toViewController.view;
[containerView addSubview:toView];
//图片背景的空白view (设置和控制器的背景颜色一样,给人一种图片被调走的假象)
UIView *imgBgWhiteView = [[UIView alloc] initWithFrame:self.transitionBeforeImgFrame];
imgBgWhiteView.backgroundColor = [UIColor clearColor];
[containerView addSubview:imgBgWhiteView];
//有渐变的白色背景
UIView *bgView = [[UIView alloc] initWithFrame:containerView.bounds];
bgView.backgroundColor = [UIColor whiteColor];
bgView.alpha = 1;
[containerView addSubview:bgView];
//过渡的图片
UIImageView *transitionImgView = [[UIImageView alloc] initWithImage:self.transitionImgView.image];
transitionImgView.frame = self.transitionAfterImgFrame;
transitionImgView.layer.cornerRadius = 20;
transitionImgView.alpha = 0.3;
transitionImgView.layer.masksToBounds = YES;
[transitionContext.containerView addSubview:transitionImgView];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
transitionImgView.frame = self.transitionBeforeImgFrame;
bgView.alpha = 0;
} completion:^(BOOL finished) {
BOOL wasCancelled = [transitionContext transitionWasCancelled];
[imgBgWhiteView removeFromSuperview];
[bgView removeFromSuperview];
[transitionImgView removeFromSuperview];
//设置transitionContext通知系统动画执行完毕
[transitionContext completeTransition:!wasCancelled];
}];
分析Push动画
我们暂不细说UIViewControllerContextTransitioning协议,我们这里只使用到了-containerView这个代理方法,我们可以通过苹果提供的键来获取对应的控制器:
ViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
获取到了fromVC,也就是当前要从哪个控制器切换。
然后通过:
DetailController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
获取到了toVC,也就是切换到哪一个控制器。
然后再通过
UIView *containerView = [transitionContext containerView];
获取containerView视图。这个是一个代理方法,可以获取到视图容器。
下面我们获取fromVC所点击的图片控件,然后通过-snapshotViewAfterScreenUpdates:将所点击的图片控件截图并用于切换使用,参数设置为NO,否则动画会很生硬。最后,我们还要将这个所点击的图片控件的坐标转换成容器视图的坐标.
UIView *toImageView = toVC.imgView;
fromImageView.hidden = YES;
toVC.view.alpha = 0.0;
toImageView.hidden = YES;
下面这两行是非常关键的,并且必须保证tempView在最上层,否则动画效果就没有了。先将目标控制器的视图添加到容器中,再添加源图片的截图到容器中,用于显示切换效果。
[containerView addSubview:toVC.view];
[containerView addSubview:tempView];
我们在动画中,将初始的截图的frame改变成最终的效果的frame即可达到我们的目标效果。另外要注意还需要将坐标转换成容器的坐标:
tempView.frame = [toImageView convertRect:toImageView.bounds toView:containerView];
当动画完成以后,一定要调用:[transitionContext completeTransition:YES],设置切换动画已经完成,否则想要pop回去就不能了。
pop和push差不多,这里就不赘述了。
如需demo,请留言。