iOS自定义转场

githubDEMO地址 是用swift实现的,oc的原理都是一样的

一.首先,为什么要用转场动画,转场动画相对于系统的push/pop,present/dismiss有什么优势?

1.如果不自定义转场modal出来的控制器会移除原有的控制器

2.如果自定义转场modal出来的控制器不会移除原有的控制器,这样可以把前面的vc当成背景来实现侧滑菜单,下拉菜单等等功能

3.如果不自定义转场modal出来的控制器的尺寸和屏幕一样

4.如果自定义转场modal出来的控制器的尺寸我们可以自定义,并且可以自定义转场动画,实现各种特效

二 我们来具体实现以下

实现步骤摘要

1.自定义一个转场动画对象,继承自UIPresentationController

2.vc1弹出vc2,设置vc2的transitioningDelegate为vc1,实现代理的三个方法,代理方法里面还要实现一个UIViewControllerAnimatedTransitioning代理。总共要实现两个代理,五个方法

下面具体介绍一下

1.自定义转场对象

class MypreVC: UIPresentationController  {

override init(presentedViewController: UIViewController, presentingViewController: UIViewController) {

super.init(presentedViewController: presentedViewController, presentingViewController: presentingViewController)

}

// 用于布局转场动画弹出的控件

override func containerViewWillLayoutSubviews(){

// 设置弹出视图的尺寸

presentedView()?.frame = CGRect.init(x: 0, y: 64, width: 200, height: (containerView?.frame.size.height)!)

// 添加透明button背景

xyf = UIButton()

xyf!.frame = UIScreen.mainScreen().bounds

containerView?.insertSubview(xyf!, atIndex: 0)

xyf?.tag = 66

xyf?.addTarget(self, action: #selector(MypreVC.funcyion2(_:)), forControlEvents: UIControlEvents.TouchUpInside)

}

private var xyf:UIButton?

func funcyion2(sender:UIButton)  {

presentedViewController.dismissViewControllerAnimated(true, completion: nil)

}

}



在第一个vc1里面有一个btn,点击弹出第二个界面

@IBAction func btnClick(sender: UIButton) {


let neextvc = NextVC()

//自定义转场动画

//设置转场代理

neextvc.transitioningDelegate = self

//动画样式

neextvc.modalPresentationStyle = UIModalPresentationStyle.Custom

//

presentViewController(neextvc, animated: true, completion: nil)

}

因为上面遵守了一个协议,现在我们来实现代理

UIViewControllerTransitioningDelegate实现

//extension ViewController:UIViewControllerTransitioningDelegate{

// 该方法用于返回一个负责转场动画的对象

// 可以在该对象中控制弹出视图的尺寸等

func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController?{

//MypreVC是我们自定义的转场对象

return MypreVC(presentedViewController: presented, presentingViewController: presenting)

}

// 该方法用于返回一个负责转场如何消失的对象

func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?{

//自定义变量,记录是否是弹出,下面的代理方法要用到

//UIViewControllerAnimatedTransitioning所以还需实现一个协议

isPresent = false

return self

}

// 该方法用于返回一个负责转场如何出现的对象

func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?{

isPresent = true

return self

}

UIViewControllerAnimatedTransitioning实现

// 告诉系统展现和消失的动画时长

// 暂时用不上

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval{

return 2

}


// 专门用于管理modal如何展现和消失的, 无论是展现还是消失都会调用该方法

/*

注意点: 只要我们实现了这个代理方法, 那么系统就不会再有默认的动画了

也就是说默认的modal从下至上的移动系统不帮再帮我们添加了, 所有的动画操作都需要我们自己实现, 包括需要展现的视图也需要我们自己添加到容器视图上(containerView)

*/

// transitionContext: 所有动画需要的东西都保存在上下文中, 换而言之就是可以通过transitionContext获取到我们想要的东西

func animateTransition(transitionContext: UIViewControllerContextTransitioning){

// 0.判断当前是展现还是消失

if isPresent {

// 通过ToViewKey取出的就是toVC对应的view

guard let toView = transitionContext.viewForKey(UITransitionContextToViewKey) else{

return

}

// 2.将需要弹出的视图添加到containerView上

transitionContext.containerView()?.addSubview(toView)

// 3.执行动画

toView.transform = CGAffineTransformMakeScale(1.0, 0.0)

// 设置锚点

toView.layer.anchorPoint = CGPoint (x: 0.5, y: 0)

UIView.animateWithDuration(2, animations: {

toView.transform = CGAffineTransformIdentity

}) { (_) in

// 注意: 自定转场动画, 在执行完动画之后一定要告诉系统动画执行完毕了

transitionContext.completeTransition(true)

}

}

else{

//dismiss

// 消失

// 1.拿到需要消失的视图

guard let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey) else{

return

}

//transitionContext.containerView()?.addSubview(toView)

// 2.执行动画让视图消失

fromView.transform = CGAffineTransformIdentity

fromView.layer.anchorPoint = CGPoint (x: 0.5, y: 0)

UIView.animateWithDuration(2, animations: {

// 突然消失的原因: CGFloat不准确, 导致无法执行动画, 遇到这样的问题只需要将CGFloat的值设置为一个很小的值即可

fromView.transform = CGAffineTransformMakeScale(1.0, 0.0001)

}) { (_) in

// 注意: 自定转场动画, 在执行完动画之后一定要告诉系统动画执行完毕了

transitionContext.completeTransition(true)

}

}

}

到上面就结束了

总结一下:

在继承自UIPresentationController的转场类中,有几个重要属性和方法

containerView属性 非常重要, 容器视图, 所有modal出来的视图都是添加到containerView上的

presentedView() 非常重要, 通过该方法能够拿到弹出的视图

func containerViewWillLayoutSubviews()用来对弹出视图做一些布局

利用好上面的内容可以把弹出的视图便成我们想要的样子

协议里面的关键是func animateTransition(transitionContext: UIViewControllerContextTransitioning){}

通过它才能实现转场动画,对转场进行控制

具体的demo:https://github.com/xuyunfan2015/CustomPresentDemo.git

你可能感兴趣的:(iOS自定义转场)