自定义转场动画
最近搭组件框架,发现转场动画有点毛病,就过来再屡屡!Demo
官方支持的4种自定义转场
- 常用的,使用栈视图控制器
UINavigationController
进行 push 和 pop Modal
转场:presentation
和dismissal
,这种方式只能在modalPresentationStyle
属性为UIModalPresentationFullScreen
或UIModalPresentationCustom
这两种模式UICollectionViewController
的布局转场:仅限于UICollectionViewController
与UINavigationController
结合的转场方式UITabBarController
中切换 Tab
前2种在以往用的比较多,所以暂时写了前2种
学习准备
- 转换动画:一个控制器的内容交换为另一个控制器的内容
转场代理 (Transitioning Delegate)
转场代理:定义并遵守 以下 协议的对象。它的工作是为UIKit提供以下对象:
(若不提供,则默认使用视图控制器的modalTransitionStyle中的标准转场动画)
1 | 三种转场代理,对应三种转场类型,这里只讲前2种 |
交互式动画对象 (Interactive animator objects)
交互式动画对象使用触摸事件或手势识别器来驱动自定义动画的时间。交互式动画对象遵守
UIViewControllerInteractiveTransitioning
协议。创建交互式动画制作者的最简单方法是将
UIPercentDrivenInteractiveTransition
子类化并将事件处理代码添加到子类中。该类控制使用现有动画对象创建的动画的时间。如果您创建自己的交互式动画制作者,则必须自己渲染动画的每个帧。我构建过程中也是继承
UIPercentDrivenInteractiveTransition
实现的
这三者之间的关系就好比是我们手动翻书:我们自己本身遵守
UIViewControllerTransitioningDelegate
,告诉手UIViewControllerInteractiveTransitioning
,应该以什么样的姿势UIViewControllerAnimatedTransitioning
翻动到下一页
我们本身很重要,既要提供手,还有摆姿势!
这些协议都是iOS 7 以后开放的
转场上下文(Transition Context):
遵守<UIViewControllerContextTransitioning>
协议
再转场动画开始前,UIKit会帮我们创建一个转场上下文,存储有关如何执行转场的信息,包括动画是否是交互式的
- 在其
animateTransition:
和transitionDuration:
方法以及startInteractiveTransition:
方法中的交互控制器中传递给动画对象。- 如果存在交互控制器,则首先调用其
startInteractiveTransition:
并将其调用到交互控制器对象,以便在需要时调用animateTransition:
方法。 - 如果没有交互控制器,则系统会自动调用动画师的
animateTransition:
方法。
- 如果存在交互控制器,则首先调用其
- 提供
viewControllerForKey:
,initialFrameForViewController:
和finalFrameForViewController:
方法,获取转场相关信息
转场协调器(Transition Coordinator):
遵守<UIViewControllerTransitionCoordinator>
协议
也是由UIKit都会创建的,视图控制器的present/dissmiss、界面旋转、frame发时发生的转场,这些变化都会造成视图层级结构的更改,协调器就是跟踪这些更改并同时为您自己的内容制作动画的方法。但仅在转场期间存在。
1 | 可通过get方法获取 |
主要在 Modal 转场和交互转场取消时使用,其他时候很少用到
UINavigationController 使用中 push 和 pop
转场代理:UINavigationControllerDelegate
(iOS 2就有了,只是到7扩充成协议便于自定义)
1 | /*返回已经实现的`动画控制器`,如果返回nil则使用系统默认的动画效果*/ |
- 自定义转场动画对象
- 自定义交互动画对象(及上面提到的自定义
UIPercentDrivenInteractiveTransition
子类)- 实现手势驱动
- 实现
UINavigationControllerDelegate
代理- 返回转场动画对象,交互动画对象
- 注意:如果在转场代理中提供了交互动画对象,而转场发生时并没有方法来驱动转场进程(比如手势),转场过程将一直处于开始阶段无法结束,应用界面也会失去响应:在 NavigationController 中点击 NavigationBar 也能实现 pop 返回操作,但此时没有了交互手段的支持,转场过程卡壳;
Modal 转场:presentation 和 dismissal
转场代理: UIViewControllerTransitioningDelegate
1 | @protocol UIViewControllerTransitioningDelegate <NSObject> |
Modal 转场的代理协议UIViewControllerTransitioningDelegate
是 iOS 7 新增的,其为 presentation
和 dismissal
转场分别提供了动画控制器。
iOS8引入了UIPresentationController
类,该类接管了 UIViewController 的显示过程。
可通过自定义UIPresentationController
的子类,覆盖相关方法
- 自定义转场动画对象
- 自定义交互动画对象(及上面提到的自定义
UIPercentDrivenInteractiveTransition
子类)- 实现手势驱动
- 实现
UIPresentationController
子类,- 重写父类方法,实现复杂的视图及动画
- 实现
UIViewControllerTransitioningDelegate
转场代理- 返回转场动画对象,交互动画对象
注意:
- 转换完成后,所有自定义动画都必须调用上下文的
completeTransition:
方法。此外,动画应该在上下文指定的containerView
中进行。对于交互式转换,应在交互式动画进行时调用上下文的updateInteractiveTransition:
,finishInteractiveTransition
或cancelInteractiveTransition
。
UIPercentDrivenInteractiveTransition
类提供了UIViewControllerInteractiveTransitioning
协议的实现,该协议可用于交互式驱动由动画对象创建的任何UIView属性动画。- Model中,在 Custom 模式下的 dismissal转场中不要像其他的转场那样将 toView(presentingView) 加入 containerView,否则presentingView将消失不见,而应用则也很可能假死。而 FullScreen 模式下可以使用与前面的容器类 VC 转场同样的代码,(Modal 转场在 Custom 模式下必须区分 presentation 和 dismissal 转场,而在 FullScreen 模式下可以不用这么做)。