自定义转场动画

最近搭组件框架,发现转场动画有点毛病,就过来再屡屡!Demo

官方支持的4种自定义转场

  1. 常用的,使用栈视图控制器 UINavigationController 进行 push 和 pop
  2. Modal 转场:presentationdismissal,这种方式只能在modalPresentationStyle属性为 UIModalPresentationFullScreenUIModalPresentationCustom这两种模式
  3. UICollectionViewController 的布局转场:仅限于 UICollectionViewControllerUINavigationController 结合的转场方式
  4. UITabBarController 中切换 Tab

前2种在以往用的比较多,所以暂时写了前2种

学习准备

  • 转换动画:一个控制器的内容交换为另一个控制器的内容

转场代理 (Transitioning Delegate)

转场代理:定义并遵守 以下 协议的对象。它的工作是为UIKit提供以下对象:
(若不提供,则默认使用视图控制器的modalTransitionStyle中的标准转场动画)

1
2
3
4
5
6
7
8
9
10
三种转场代理,对应三种转场类型,这里只讲前2种

//push、pop
<UINavigationControllerDelegate> //UINavigationController 的 delegate 属性遵守该协议。

//tab转换
<UITabBarControllerDelegate> //UITabBarController 的 delegate 属性遵守该协议。

//modal
<UIViewControllerTransitioningDelegate> //UIViewController 的 transitioningDelegate 属性遵守该协议。
  • 动画对象 (animator objects)
    负责创建用于显示或隐藏视图控制器视图的动画。动画对象遵守UIViewControllerAnimatedTransitioning协议。
  • 交互式动画对象 (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
2
可通过get方法获取
@property(nonatomic, readonly, nullable) id <UIViewControllerTransitionCoordinator> transitionCoordinator NS_AVAILABLE_IOS(7_0);

主要在 Modal 转场和交互转场取消时使用,其他时候很少用到

UINavigationController 使用中 push 和 pop

转场代理:UINavigationControllerDelegate (iOS 2就有了,只是到7扩充成协议便于自定义)

1
2
3
4
5
/*返回已经实现的`动画控制器`,如果返回nil则使用系统默认的动画效果*/
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);

/*返回已经实现的`交互控制器`,如果返回nil则不支持手势交互*/
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);
  1. 自定义转场动画对象
  2. 自定义交互动画对象(及上面提到的自定义UIPercentDrivenInteractiveTransition 子类)
    • 实现手势驱动
  3. 实现UINavigationControllerDelegate 代理
    • 返回转场动画对象,交互动画对象
  • 注意:如果在转场代理中提供了交互动画对象,而转场发生时并没有方法来驱动转场进程(比如手势),转场过程将一直处于开始阶段无法结束,应用界面也会失去响应:在 NavigationController 中点击 NavigationBar 也能实现 pop 返回操作,但此时没有了交互手段的支持,转场过程卡壳;

转场代理: UIViewControllerTransitioningDelegate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@protocol UIViewControllerTransitioningDelegate <NSObject>

@optional
/*present时调用,返回已经实现的`动画控制器`*/
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;

/*dissmis时调用,返回已经实现的`动画控制器`*/
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;

/*交互动画present时调用,返回已经实现的`交互控制器`*/
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator;

/*交互动画dissmiss时调用,返回已经实现的`交互控制器`*/
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;

/*ios8新增的协议*/
- (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(nullable UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0);

@end

Modal 转场的代理协议UIViewControllerTransitioningDelegate是 iOS 7 新增的,其为 presentationdismissal 转场分别提供了动画控制器。
iOS8引入了UIPresentationController类,该类接管了 UIViewController 的显示过程。
可通过自定义UIPresentationController的子类,覆盖相关方法

  1. 自定义转场动画对象
  2. 自定义交互动画对象(及上面提到的自定义UIPercentDrivenInteractiveTransition 子类)
    • 实现手势驱动
  3. 实现UIPresentationController子类,
    • 重写父类方法,实现复杂的视图及动画
  4. 实现UIViewControllerTransitioningDelegate 转场代理
    • 返回转场动画对象,交互动画对象

注意:

  • 转换完成后,所有自定义动画都必须调用上下文的completeTransition:方法。此外,动画应该在上下文指定的containerView中进行。对于交互式转换,应在交互式动画进行时调用上下文的updateInteractiveTransition:finishInteractiveTransitioncancelInteractiveTransition
  • UIPercentDrivenInteractiveTransition类提供了UIViewControllerInteractiveTransitioning协议的实现,该协议可用于交互式驱动由动画对象创建的任何UIView属性动画。
  • Model中,在 Custom 模式下的 dismissal转场中不要像其他的转场那样将 toView(presentingView) 加入 containerView,否则presentingView将消失不见,而应用则也很可能假死。而 FullScreen 模式下可以使用与前面的容器类 VC 转场同样的代码,(Modal 转场在 Custom 模式下必须区分 presentation 和 dismissal 转场,而在 FullScreen 模式下可以不用这么做)。

示例图

推荐文章:

感谢您的阅读,本文由 Anrue 版权所有。如若转载,请注明出处:Anrue(https://github.com/anru1314/2018/10/09/iOS/2018-10-09-自定义转场动画/
iOS 定时器
MySql笔记