1.需求确认
在HomeViewController中, 点击TitleButton, 通过自定义转场动画的方式modal出一小块的PopoverViewController
2.类索引
1) HomeViewController : BaseViewController
-- "源控制器", 负责发起自定义转场
2) PopoverViewController : UIViewController
-- "目标控制器", 通过自定义转场而被展现
3) PopoverPresentationController : UIPresentationController
-- "转场控制器", 负责配置自身容器属性, 将目标控制器的view添加到容器中, 容器本质也是一个view
4) PopoverAnimator : NSObject
-- 自定义转场动画类, 用于将下面两个代理中的方法从源控制器中进行抽离, 使源控制器只保留逻辑代码, 保证其代码的整洁和优雅
5) UIViewControllerTransitioningDelegate
-- 常用三个代理方法, 用于告诉系统谁是转场控制器, 谁负责转场动画的开始, 谁负责转场动画的结束
6) UIViewControllerAnimatedTransitioning
-- 常用两个代理方法, 用于告诉系统转场动画的持续时间与实现
3.实现步骤
1) 设置目标控制器的代理对象
popoverViewController.transitioningDelegate = 自定义转场动画类的实例化对象
2) 设置目标控制器的转场样式
popoverViewController.modalPresentationStyle= UIModalPresentationStyle.Custom
3) 自定义转场控制器类 PopoverPresentationController : UIPresentationController
在这个类中, 着重使用了两个属性, 并重写两个方法:
containerView : 容器属性, 所有被展现的东西都在这个view内部
presentedView() : 返回目标控制器的view
init(presentedViewController, presentingViewController)
初始化方法, 记得调用'super.'对父类初始化
第一个参数: 目标控制器
第二个参数: 在Xcode6为nil, Xcode7为野指针
containerViewWillLayoutSubviews()
容器布局方法, 该方法会在转场前进行调用, 对容器内的视图进行统一配置(包括: 目标控制器的view.frame、coverView等)
4) 实现UIViewControllerTransitioningDelegate的最主要代理方法
presentationControllerForPresentedViewController(presented,presenting, source)
-> UIPresentationController?
该代理方法告诉系统, 谁是转场控制器
参数一: 目标控制器
参数二: 在Xcode6为nil, Xcode7为野指针
参数三: 源控制器
返回值: 转场控制器
5) 实现UIViewControllerTransitioningDelegate的另外两个代理方法
animationControllerForPresentedController(presented, presenting, source)
-> UIViewControllerAnimatedTransitioning?
该代理方法告诉系统, 谁负责转场动画的展现, 在展现开始前被调用
返回值: 签订UIViewControllerAnimatedTransitioning协议的对象, 这里返回转场动画类
animationControllerForDismissedController(dismissed)
-> UIViewControllerAnimatedTransitioning?
该代理方法告诉系统, 谁负责转场动画的消失, 在消失开始前被调用
返回值: 签订UIViewControllerAnimatedTransitioning协议的对象, 这里返回转场动画类
6) 实现UIViewControllerAnimatedTransitioning的两个代理方法
transitionDuration(transitionContext) ->NSTimeInterval
该代理方法告诉系统, 转场动画的执行时间
animateTransition(transitionContext)
在该代理方法中完成动画的实现, 无论展现还是消失,都会调用这个方法
参数: transitionContext, 里面包含了动画需要的所有参数!
通过 transitionContext.viewControllerForKey(key) 获取目标控制器和源控制器
通过 transitionContext.viewForKey(key) 获取展现的view和消失的view
通过 transitionContext.containerView 获取转场控制器的容器属性
通过 transitionDuration(transitionContext) 设置动画持续时间
通过 transitionContext.completeTransition(true), 动画完成时告诉系统, 该步必须有!
7) 一切准备就绪, 调用modal方法吧
presentViewController(homeVC, animated:true, completion:nil)
4.注意事项
1) 自定义转场需要iOS8以上版本
2) 默认转场会将源控制器的view替换成目标控制器的view, 而自定义转场,不会移除源控制器的view
3) 重写步骤5和6里面的代理方法后, 系统自带的转场动画(从下至上)就已经没有了
4) 在代理方法animateTransition(transitionContext)中, 通过使用transitionContext.viewForKey(key)获取到要展现的视图后,一定要将其添加到容器中, 否则弹窗弹不出来!
5) 在转场动画完成后, 一定要调用transitionContext.completeTransition(true), 否则会产生各种未知的问题(如同在layoutSubviews()中不调用super一样)
6) 在UIView.animateWithDuration()中, 如果调用了CGAffineTransformMakeScale等参数类型为CGFloat的方法, 填0.0会没有动画, 由于系统缺陷导致CGFloat类型是不准确的.