之前有写过一篇文章讲的是使用pop控制器UIPopoverPresentationController实现控制器的pop效果,不过他是没有动画的,也有试过把专访动画的代码加到控制器中单没有成功,如果有大神的话还请多多指教
后来就通过控制器的转场代理来手动计算添加你需要的转场动画transitioningDelegate
下面就写一段试例代码
func clickbtn()
{
//创建一个需要pop的控制器这里我自定义一个类名叫mycontroller的自定义控制器
let mycon = mycontroller()
//设置控制器的转场代理
mycon.transitioningDelegate = self
//这里需要设置控制器的样式为自定义样式,不然弹出控制器后之前的
//控制器就会被释放,这样背景就是黑的了
mycon.modalPresentationStyle = UIModalPresentationStyle.Custom
//莫泰出我们的控制器
presentViewController(mycon, animated: true, completion: nil)
}
//既然设置了代理就需要实现代理方法这里需要实现三个方法
extension ViewController : UIViewControllerTransitioningDelegate{
/// 返回一个控制展现(显示)的对象.这个对象里面可以设置modal出来的控制器的view的大小
func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController? {
// 这个方法需要返回一个UIPresentationController对象
// 创建一个类继承UIPresentationController的类,然后返回
// 注意,不能调用空参数的构造方法不然会报: NSetM addObject: obj不能为nil
return myPresentationController(presentedViewController: presented, presentingViewController: presenting)
}
/// 返回一个控制modal时的动画的对象
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// 1.创建一个类实现UIViewControllerAnimatedTransitioning
// 2.用这个类创建对象,并返回回去
return myPopoverAnimation()
}
/// 返回一个控制dismiss时的动画的对象
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// 1.创建一个类实现UIViewControllerAnimatedTransitioning
// 2.用这个类创建对象,并返回回去
return myDismissAnimation()
}
}
//既然需要返回一个UIPresentationController对象,我们就创建一个继承UIPresentationController的对象
class myPresentationController : myPresentationController
{
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
//可以将背景视图添加到容器视图并可以点击它就退出
containerView?.addSubview(backView)
//添加约束
backView.translatesAutoresizingMaskIntoConstraints = false
containerView?.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: containerView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0))
containerView?.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: containerView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0))
containerView?.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: containerView, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0))
containerView?.addConstraint(NSLayoutConstraint(item: backView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: containerView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0))
// 将背景视图推到最底部
containerView?.sendSubviewToBack(backView)
// 获取modal出来的控制器的view
let modalView = presentedView()
// 修改modal出来的控制器的view 的大小
modalView?.frame = CGRect(x: 100, y: 56, width: 200, height: 300)
}
//声明一个背景的view
private lazy var backView: UIView = {
let view = UIView()
// 设置背景颜色0.3的白(灰色)透明度0.2(1为不透明)
view.backgroundColor = UIColor(white: 0.3, alpha: 0.2)
// 添加点击的手势也可以直接设置一个button
let tap = UITapGestureRecognizer(target: self, action: "backViewClick")
view.addGestureRecognizer(tap)
return view
}()
func backViewClick()
{
// 获取到modal出来的控制器,并关闭ted已经莫泰出的控制器
presentedViewController.dismissViewControllerAnimated(true, completion: nil)
//如果想在点击背景的时候再多加一些其它操作可以发送一个通知这个看大家的需要了
}
}
//创建一个继承UIViewControllerAnimatedTransitioning的累作为莫泰出控制器时的动画在这个累里需要实现两个父累方法
class myPopoverAnimation : NSObject,UIViewControllerAnimatedTransitioning
{
// 转场动画的时间
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.25
}
// 具体实现转场动画
// 注意: 当实现这个方法后,需要我们手动将元素添加到容器视图,充分地让我们自定义转场动画
//注意:这里的两个key UITransitionContextToViewKey 和 UITransitionContextFromViewKey
//可以看作当你在莫泰出的时候是从一开始的控制器到莫泰的控制器所以UITransitionContextToViewKey是莫泰而UITransitionContextFromViewKey是开始的控制器在你dismiss的时候是相反的因为你时要从莫泰回到最开始的
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// 获取到modal出来的控制器的view
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
// 将modal出来的控制器的view添加到容器视图
transitionContext.containerView()?.addSubview(toView)
// 设置y方向的缩放
toView.transform = CGAffineTransformMakeScale(1, 0)
// 修改锚点
toView.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
// 做动画
UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
// 清空transform
toView.transform = CGAffineTransformIdentity
}) { (_) -> Void in
// 调用completeTransition告诉系统转场动画完成了
transitionContext.completeTransition(true)
}
}
class myDismissAnimation : NSObject,UIViewControllerAnimatedTransitioning
{
// 转场动画的时间
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.25
}
// 具体实现转场动画
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// 1. 获取到modal出来的控制器的view
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
// 2. 做动画
UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
// 注意: s缩放的Y值不能写0,如果填0就没有动画效果了
fromView?.transform = CGAffineTransformMakeScale(1, 0.0001)
}) { (_) -> Void in
// 告诉系统关闭的转场动画完成了
transitionContext.completeTransition(true)
}
}
}
}
具体的效果大家可以根据自己的需要去计算