Skip to content

Instantly share code, notes, and snippets.

@Josscii
Last active July 21, 2017 02:23
Show Gist options
  • Save Josscii/5be32a8f4be6f8f1a8ea8042d175f091 to your computer and use it in GitHub Desktop.
Save Josscii/5be32a8f4be6f8f1a8ea8042d175f091 to your computer and use it in GitHub Desktop.
自定义转场

自定义转场

iOS 中自定义转场指的是 view controller 之间的切换,分为两种类型:

  • model presentation
  • navigation push/pop

系统为这两种类型都提供了默认的实现,对于 model presentation 来说,还可以通过指定 modalTransitionStyle 来达到不同的转场效果。

protocol 解释

当然,我们也可以通过实现一系列的 protocol 来自定义转场。

  • UIViewControllerContextTransitioning,transition context 对象,顾名思义,就是用来记录上下文信息的,由系统创建并传递给 animator 和 interaction controller。
  • UIViewControllerAnimatedTransitioning,一般把实现该接口的对象称为 animator,主要用来完成转场动画。
  • UIViewControllerInteractiveTransitioning,一般把实现该接口的对象称为 interaction controller,主要用来完成交互式转场。
  • UIViewControllerTransitioningDelegate,用于指定 view controller 转场时需要用到的 animator 或者 interaction controller等。

动画转场

对于普通的动画转场来说,需要分为两种情况,搞混这两种情况很容易触发一些奇怪的 bug,并且在低版本的 iOS 系统上很可能会失效。

在 iOS 8 之前,sdk 只为我们提供了 animator 的方式来实现转场动画,需要两步:

  • 实现 UIViewControllerTransitioningDelegate,给要被 present 的 VC 的 transitioningDelegate 赋值。
  • 实现 UIViewControllerAnimatedTransitioning,在 animateTransition: 中对 toView 和 fromView 做动画。

这里有几个值得注意的问题:

第一,首先要搞清楚 modalPresentationStyle 这个值,默认是 FullScreen,也就是全屏转场,全屏转场有其特殊性,在 presenting 过后,fromView 会被移除,所以如果你想在这个模式下做一些非全屏的转场,换句话说 toView 不会覆盖住整个屏幕,那么你会在 presenting 过后得到一个黑色的背景,解决办法是在 finish 过后将 fromView 添加到 toView 之下。

第二,无论是在 present 还是 dismissal 过程中,fromView已经被自动添加到 containerView 上,而 toView 始终都是需要你手动添加到 containerView 上去的,两个过程中 toViewfromView 是互换的,所以对于不同过程,两个 view 的初始状态和结束状态需要理清楚。

第三,无论是在官方文档还是在其他博文中,普遍的做法是借助一个标志量 presenting 来区分两个过程,为的是复用代码,但是经过我实践发现,这样做很容易把两个过程搞混淆,我建议最好使用两个不同的 animator。

为了实现非全屏即自定义的转场,从 iOS 8 开始,sdk 为我们提供了一个 UIPresentationController 的类来封装 modal presentation 的逻辑,这个类的出现,一定程度上是为了简化自定义转场中屏幕尺寸的适应问题。

使用这个类来自定义转场,需要做到三步:

  • 设置 presented view controller 的 modalPresentationStyle 为 custom。
  • 实现 UIViewControllerAnimatedTransitioning 中的 presentationControllerForPresentedViewController 方法,并且给 presented view controller 的 transitionDelegate 赋值。
  • 自定义 UIPresenttationController 的子类,重写里面的方法,对 presented view 做一些自定义。
  • 实现 UIViewControllerAnimatedTransitioning,在 animateTransition: 中对 toView 和 fromView 做动画。

custom 与 fullScreen 不同的是在 presenting 过后不会移除 fromView,所以在 dismissal 的过程中 toView 就不用我们手动添加了。

交互式转场

交互式转场相当于给动画转场锦上添花,所以实现交互转场的前提是要先实现动画转场。苹果已经为我们做好了封装一个 UIPercentDrivenInteractiveTransition,我们只需要做的是,给需要手势驱动的过程的 view 加上手势,然后在回调函数中更新动画进度。对于 present 来说,在手势开始时,需要调用 present:animated 方法,对于 dismissal 来说,则需要调用 dismiss:completion 方法。这个过程可以封装在 UIPercentDrivenInteractiveTransition 的子类中,也可以直接写在 view controller 中。

自定义导航控制器 push

通过查看 api 可以看到,在 UINavigationControllerDelegate 中提供了和 UIViewControllerTransitioningDelegate 类似的方法,在这里指定了 animator 和 interaction controller 后就和之前的没什么区别了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment