iOS ViewContrller转场动画学习笔记

iOS ViewContrller转场动画学习笔记

本文只用来记录学习的modal方式的转场,一般需要实现的动画包括:presentation,dismissal两种可能实现的动画.

FromView 和 ToView

在代码中,经常使用FromViewToView.FromView表示当前的视图view,ToView表示要跳转的视图View.例如,presentation中,Avc present 出 Bvc,则A的view视图就是FromView,而B的view就是ToView.相反,dismissal中,从Bvc dismiss 到Avc,此时Bvc的视图view就是FromView,A的视图view就是ToView.

Presenting和presented

这组概念也很重要,容易和上面的FromView,ToView混淆.如果是Avc present Bvc,那么A就是Presenting,B就是presented.不论当时的动作是Presentation还是Dismissal.UIKit中讲A称为presentingViewController,B称为presentedViewController.通过主动或者被动很容易区分出来.

modalPrentationStyle

viewController中关于modal相关的属性: FullScreenCustom两种.区别在与FullScreen时候在containerView中会主动移除fromView,而Custom模式中,containerView不会主动移除fromView.

这个属性的特点非常重要.如果需要present方式时候想看到presentingViewController的view,那么这里一定要设置成Custom.

自定义转场动画

最简单的转场动画需要如下步骤:

  • 创建一个遵守UIViewControllerAnimatedTransitioning协议的对象
  • 实现该协议的两个重要的方法
//指定转场动画持续的时长
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval      
//转场动画的具体内容       
func animateTransition(transitionContext: UIViewControllerContextTransitioning)
  • 使得presentingViewController或者创建一个类遵守UIViewControllerTransitioningDelegate协议,并且实现如下两个方法,返回一个前面创建的满足Animation协议的对象
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
  • 设置presentedViewController的transitioningDelegate属性

上面步骤中,所有的动画都在func animateTransition(transitionContext:)中完成,这里需要发挥你的想象力.具体的FromViewToView的动画如何展现.

特殊的Modal转场

这里直接引用的参考文章中的内容 -- 非常重要

Modal 转场中需要做的事情和两种容器 VC 的转场一样,但在细节上有些差异。UINavigationController 和 UITabBarController 这两个容器 VC 的根视图在屏幕上是不可见的(或者说是透明的),可见的只是内嵌在这两者中的子 VC 中的视图,转场是从子 VC 的视图转换到另外一个子 VC 的视图,其根视图并未参与转场;而 Modal 转场,以 presentation 为例,是从 presentingView 转换到 presentedView,根视图 presentingView 也就是 fromView 参与了转场。而且 NavigationController 和 TabBarController 转场中的 containerView 也并非这两者的根视图。

Modal 转场与两种容器 VC 的转场的另外一个不同是:Modal 转场结束后 presentingView 可能依然可见,UIModalPresentationPageSheet 模式就是这样。这种不同导致了 Modal 转场和容器 VC 的转场对 fromView 的处理差异:容器 VC 的转场结束后 fromView 会被主动移出视图结构,这是可预见的结果,我们也可以在转场结束前手动移除;而 Modal 转场中,presentation 结束后 presentingView(fromView) 并未主动被从视图结构中移除。准确来说,是 UIModalPresentationCustom 这种模式下的 Modal 转场结束时 fromView 并未从视图结构中移除;UIModalPresentationFullScreen 模式的 Modal 转场结束后 fromView 依然主动被从视图结构中移除了。这种差异导致在处理 dismissal 转场的时候很容易出现问题,没有意识到这个不同点的话出错时就会毫无头绪。下面来看看 dismissal 转场时的场景。

ContainerView 在转场期间作为 fromView 和 toView 的父视图。三种转场过程中的 containerView 是 UIView 的私有子类,不过我们并不需要关心 containerView 具体是什么。在 dismissal 转场中:

  • UIModalPresentationFullScreen 模式:presentation 后,presentingView 被主动移出视图结构,在 dismissal 中 presentingView 是 toView 的角色,其将会重新加入 containerView 中,实际上,我们不主动将其加入,UIKit 也会这么做,前面的两种容器控制器的转场里不是这样处理的,不过这个差异基本没什么影响。
  • UIModalPresentationCustom 模式:转场时 containerView 并不担任 presentingView 的父视图,后者由 UIKit 另行管理。在 presentation 后,fromView(presentingView) 未被移出视图结构,在 dismissal 中,注意不要像其他转场中那样将 toView(presentingView) 加入 containerView 中,否则本来可见的 presentingView 将会被移除出自身所处的视图结构消失不见。如果你在使用 Custom 模式时没有注意到这点,就很容易掉进这个陷阱而很难察觉问题所在,这个问题曾困扰了我一天。

小结:建议是,不要干涉官方对 Modal 转场的处理,我们去适应它。在 Custom 模式下,由于 presentingView 不受 containerView 管理,在 dismissal 转场中不要像其他的转场那样将 toView(presentingView) 加入 containerView,否则 presentingView 将消失不见,而应用则也很可能假死;在 presentation 转场中,切记不要手动将 fromView(presentingView) 移出其父视图。

iOS 8 为协议添加了viewForKey:方法以方便获取 fromView 和 toView,但是在 Modal 转场里要注意,从上面可以知道,Custom 模式下,presentingView 并不受 containerView 管理,这时通过viewForKey:方法来获取 presentingView 得到的是 nil,必须通过viewControllerForKey:得到 presentingVC 后来获取。因此在 Modal 转场中,较稳妥的方法是从 fromVC 和 toVC 中获取 fromView 和 toView。

总结要点

  • 一般来说,Modal 转场的delegate由 presentedVC 提供
  • 在presentation/push时候,要调用containerView.addSubView(toView),toView加入到containerView是每个转场必须完成的一步.modal中的Custom模式下的Dismiss 里不要将 toView添加到containerView,因为在present的时候,系统就没有将它从containerView中删除.
  • 在UIView.animation的completion中要调用如下代码:
//2
let isCancelled = transitionContext.transitionWasCancelled()
transitionContext.completeTransition(!isCancelled)
  • Modal 转场一般需要 presentedVC 来提供转场UIViewControllerTransitioningDelegate的代理. modal方式中自定义转场时,决定转场动画效果的modalTransitionStyle属性将被忽略.具体动画由代理中返回的animationController决定

参考文献

https://github.com/wazrx/XWTrasitionPractice

http://www.jianshu.com/p/45434f73019e

http://www.cocoachina.com/ios/20160309/15605.html

偶然遇到的crash:

1 怎么连续dismiss两个viewController?
直接[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];就可以了,控制器堆栈是dismiss掉下面的,上面的自动就dismiss了.或者直接将动画设置成No

2 连续push或者present会crash - 因为动画的问题.如果有此类需求.直接关闭动画

你可能感兴趣的:(iOS ViewContrller转场动画学习笔记)