「精通」这个词不敢瞎讲,不过本文大体能够帮助你达到副标题的水平的:熟读几遍,多写几遍,转场就掌握了。另外,大家所谓的转场动画=转场+动画,其实两者互不相关,不管是简单的转场动画还是炫酷的转场动画,你想要的效果那是动画的事情,完全是另外一个话题。
简书里不支持目录跳转以及排版页面过窄使得阅读这个长篇很不方便,文章已经搬运至我的 Github Wiki 里。
文章目录
看这目录挺吓人的,其实转场是非常简单的事情,当你照着随便哪里的入门教程写下第一个非交互式转场动画后,你就已经掌握了转场50%的内容了,剩下的50%有点坑容易掉进去,不过多写几次,基本上就全掌握了。但是,这不能保证你能写出你想要的动画,因为这得看你会不会那个动画,日常够用的动画很简单,大部分动画库里的例子绝对足够你使用了,比如 Spring,很多基础动画,我早期学习动画案例都是从这里抄。这些动画已经能够组合出绝大部分你看到的转场动画了,实际上很多动画在于你是否能够将其分解成基础的动画,这是经验的问题,多写写多看看,而一些剩下的奇技淫巧的动画则需要一些特别的知识,比如用贝塞尔曲线实现一些非规则形状的动画,这得去了解 UIBezierPath + CAShapeLayer + maskLayer,教程也有不少。另外推荐这个关于 CAlayer 的教程,很多特殊的动画得依靠它们来实现。
版权申明:我已将本文在微信公众平台的发表权「独家代理」给 iOS 开发(iOSDevTips)微信公共帐号。扫码关注「iOS 开发」:
iOSDevTips
Demo 更新了 Swift 3.0,而文章中的代码片段由于工作量挺大的,看时间更新。












网友评论
let transitionType = SDETransitionType.navigationTransition(.push)
return SlideAnimationController(type: transitionType)
dismiss 方法中返回的是.pop类型controller
我用了PresentationController把dimmingView加到containerView上,dimmingView是一个黑色alpha为0的UIVisualEffectView,然后presentation时用动画控制它的alpha到0.5,dismissal时用动画控制它的alpha回到0。
我在presentedViewController上加了一个拖动手势,我用这个手势更新交互控制器,但我在调试的时候发现PresentationController的动画和AnimatedTranstitioning不同步,我用NSLog打印手势更新的percent,发现percent在0.5时,presentedView就已经全部到右边消失了,但是dimming有alpha还没有到0.0,所以好像AnimatedTranstitioning只占了动画周期的一半
下面是我的代码:
https://github.com/xypng/TransitionAnimationDemo
谁能帮我看看,这是我的代码:
https://github.com/xypng/TransitionAnimationDemo
下面我稍微解释一下代码:
我是从PresentingViewController点击present按钮,用presentViewController:animated:completion:方法,present到PresentedViewController,
PresentedViewController的modalTransitionStyle(设成了UIModalPresentationCustom)和transitioningDelegate(实例化了一个我自己写的代理,这个代理是全局的,解决了代理是弱引用的问题)属性是在init时设置的。
但是我运行结束后后面就黑了,我用debug view hierarchy查看,发现viewFrom被移除了。可是文章第一部分特殊的 Modal 转场不是说 Custom 模式:presentation 结束后,presentingView(fromView) 未被主动移出视图结构
我现在是在panGesture里进行的图片跟随手指移动的动画,这点应该是没错的,然后手势结束之后,需要做frame动画,代码是这样的:
case UIGestureRecognizerStateEnded:{
//NSLog(@"----UIGestureRecognizerStateEnded");
[sender setTranslation:CGPointZero inView:sender.view.superview];
self.interacting = NO;
[self finishInteractiveTransition];
[UIView animateWithDuration:self.duration delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowUserInteraction animations:^{
self.animationController.initialView.alpha = 0.0;
self.animationController.destinationView.alpha = 1.0;
NSLog(@"---------self.animationController.initialView.frame = %@",NSStringFromCGRect(self.animationController.initialView.frame));
NSLog(@"---------self.animationController.destinationView.frame = %@",NSStringFromCGRect(self.animationController.destinationView.frame));
self.animationController.initialView.frame = self.animationController.destinationFrame;
self.animationController.destinationView.frame = self.animationController.destinationFrame;
} completion:^(BOOL finished) {
[self.animationController.initialView removeFromSuperview];
[self.animationController.destinationView removeFromSuperview];
[self.transitionContext completeTransition:YES];
}];
}
现在有一个很奇怪的现象是我如果移动的距离不大的话,动画是没有问题的,但是如果移动幅度过大(图片只在屏幕上留下一个小角落)的时候,动画就会卡顿或者直接就不执行了...不知道为什么?请问楼主有没有什么建议,谢谢!
`。然而现在的问题是,我该如何做出 present 卡片vc 的过程中,点击 dimView 取消 present 过程呢?请问是否能给我一些思路呢?谢谢。
所以我觉得在转场上下文调用动画控制器animateTransition()方法之前调用fromViewCotroller的willMoveToParentViewController(nil)方法,这样能保证fromViewCotroller的正常声明周期调用,比方说你在动画控制器里调用fromViewCotroller.view移除的动画之前,可以保证在此之前fromViewCotroller 的viewWillAppear调用,而不是动画控制器完成移除之后才调用这些声明周期函数
if (toVC.isBeingPresented) {
toView.bounds = CGRectMake(0, 0, containerView.frame.size.width * 2 / 3, containerView.frame.size.height * 2 / 3);
toView.center = containerView.center;
toView.alpha = 0;
[containerView addSubview:toView];
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 options:(UIViewAnimationOptionCurveEaseOut) animations:^{
toView.bounds = CGRectMake(0, 0, containerView.frame.size.width, containerView.frame.size.height);
toView.alpha = 1;
fromView.transform = CGAffineTransformMakeTranslation(containerView.frame.size.width, 0);
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
if (progress > 0.5) {
self.tabBarVCDelegate.interactionController.completionSpeed = 1 - progress;
[self.tabBarVCDelegate.interactionController finishInteractiveTransition];
}else {
//取消转场后,UITabBarController会自动恢复selectedIndex的值,不需要手动恢复
self.tabBarVCDelegate.interactionController.completionSpeed = 1 - progress;
[self.tabBarVCDelegate.interactionController cancelInteractiveTransition];
}
UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
fromView.transform = fromViewTransform
toView.transform = CGAffineTransformIdentity
}, completion: { finished in
fromView.transform = CGAffineTransformIdentity
toView.transform = CGAffineTransformIdentity
let isCancelled = transitionContext.transitionWasCancelled()
transitionContext.completeTransition(!isCancelled)
})
引起的
從頭到尾都看了一遍 :)