自定义转场动画--蒙板(Swift)

第一次在上面写东西,算是对自己的一些学习情况进行记录。如果有哪里表述的不太清楚请大家多多包涵。929562459这是我的QQ大家可以一起进行一些交流。
最近在做一个项目,在播放视频的时候push(这个viewController暂称为A)到播放视频的viewController(暂称为B)时需要一个过渡动画,手上没有相对应的视频,给大家口述一下:从A push 到B的时候从屏幕右下角开始出现一个四分之一的圆形。随着圆形的扩大A消失B显示出来。从B pop到A的时候恰好是相反的。在使用蒙板做的时候需要记住一点就可以了给一个UIView或者UIView的子类添加一个蒙板的时候,该UIView只会显示和该蒙板重合的地方,其余的部分则是这个UIView下层的UIView. 举个例子假设一个ViewController的view的背景色为红色,给它添加一个子视图,子视图的frame为(0,0,view.bounds.size.width,view.bounds.size.height)设置背景色为黄色。给子视图添加一个蒙板层,蒙版的宽度和子视图的宽度相同,高度为子视图的一半,这时看到的效果则是一半为红色一半为黄色。下面是部分代码:

class A : UIViewController, UINavigationControllerDelegate {
  let popAnimation = PopViewAnimation()  //下面给出这个动画的实现
  override func viewDidLoad() {
    //......
     navigationController.delegate = self
    //......
  }
func navigationController(navigationController: UINavigationController,animationControllerForOperation operation: UINavigationControllerOperation,fromViewController fromVC: UIViewController,toViewController toVC: UIViewController)->UIViewControllerAnimatedTransitioning? {
    //在这里需要注意的是如果从A 可以push 到B C D 等多个ViewController 但是只有从A push 到B时才有动画可以在下面加上
    if operation == .Push { // && toVC is xxxViewController(目标ViewController)
      return popAnimation
    }
    return nil
   }
}
//跳转动画的实现
class PopViewAnimation : NSObject,UIViewControllerAnimatedTransitioning {
    
    // 屏幕宽度
    let width: CGFloat = UIScreen.masinScreen().bounds.size.width
    //屏幕高度
    let height: CGFloat = UIScreen.mainScreen().bounds.size.height
    //遮罩层
    let maskLayer = CAShapeLayer()
    //设置遮罩层初始路径大小
    let originFrame = CGRect(x:width,y:height,width:1,height:1)
    var radio: CGFloat = 0  
    private var transitionContext : UIViewControllerContextTransitioning!

    func transitionDuration(transitionContext:             UIViewControllerContextTransitioning?) -> NSTimeInterval { 
    return 2 //动画持续的时间
  }

  func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    
    //圆形半径  勾股定理哈哈 圆形半径为屏幕对角宽度 四分之一圆刚好可以遮盖屏幕
    radio = sqrt(width*width + height*height)

    let originPath = UIBezierPath(OvalInRect:originFrame).CGPath
    //CGRectInset 有三个参数 rect dx dy 将rect的宽度的和高度缩小多少倍,因为我们在这里需要扩大多少倍所以选择-radio
    let destPath = UIBezierPath(OvalInRect:CGRectInset(originFrame,dx:-radio,dy:-radio)).CGPath

    //A ViewController
     let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) 

    //B ViewController
    let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
    maskLayer.path = originPath    
    toVC.view.layer.mask = maskLayer  

    //在这里需要注意了,因为我们需要在动画执行的过程中A慢慢消失,B慢慢出现,根据上面所说的遮罩层没有遮罩的地方将显示该View下面的View.在这里A和B的层级关系就是B在A的上面,当B的罩着层慢慢扩大时,随着B慢慢显示A逐渐消失,明白这点就容易多了.

    //将B的View添加到A的View上面
   // transitionContext.containerView()?.insertSubview(toVC.view, aboveSubview: fromVC.view)
    //将B 的View移动到最上层
    transitionContext.containerView()?.bringSubViewToFront(toVC.view)
    self.transitionContext = transitionContext    

    let animation = CABasicAnimation(keyPath: "path")
    animation.fromValue = originPath 
    animation.toValue = destPath 
    animation.duration = 2.0
    animation.delegate = self
    maskLayer.addAnimation(animation, forKey: "path")

  }
  
  //动画执行完成后执行
  override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
    //上面那个动画执行完成后,maskLayer会返回到执行动画前的状态,有 属性可以设置保存执行完动画的状态。在这里我重新设置为执行完动画后的状态
    maskLayer.path = UIBezierPath(ovalInRect:CGRectInset(originFrame, -radio, -radio)).CGPath
    //用于通知动画执行完成
    transitionContext.completeTransition(true)
  }
}

第一次在上写东西,也不知道这个格式对不对,如果不对的话大家请到这里传送门

你可能感兴趣的:(自定义转场动画--蒙板(Swift))