swift 转场动画 从左到右

原文链接
转场动画

需求:

  • 点击导航栏左上角,出现一个左侧菜单
  • 左侧菜单覆盖住 原控制器的一半
  • 左侧菜单的出现顺序为:从左至右
swift 转场动画 从左到右_第1张图片
Snip20170704_9.png

实现

  • 左侧菜单为 UIViewController,
  • UIViewController 半透明状态,可以看到 原控制器的数据
  • 使用转场动画实现左侧菜单的动画效果
  • 使用 modalPresentationStyle 做出 半透明效果
  • ViewController 控制器为 第一控制器, 以后简称 A控制器。
  • SecondVC 控制器为 第二控制器,以后简称 B控制器
  • FadeAnimator 类 是 用来写 转场动画的类。

demo地址

demo地址

实现代码

  • 在 FadeAnimator 类中实现 动画,代码如下:
//
//  FadeAnimator.swift
//  LeftView
//
//  Created by study on 2017/6/30.
//  Copyright © 2017年 WY. All rights reserved.
//

import UIKit


enum AnimationType {
    case present
    case dismiss
}

class FadeAnimator: NSObject , UIViewControllerAnimatedTransitioning {
    
    let duration = 1.5
    var animationType: AnimationType?
    
    
    // 指定转场动画持续的时间
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        
        let toView = toViewController?.view
        let fromView = fromViewController?.view
        
        let transitionTime = transitionDuration(using: transitionContext)
        let aDelay: TimeInterval = 0
        let aUsing: CGFloat = 0.5
        let aInitSprVel: CGFloat = 0
        
        if animationType == AnimationType.present {
            
            //snapshot方法是很高效的截屏

            // first 放下面
            let snap = fromView?.snapshotView(afterScreenUpdates: true)
            transitionContext.containerView.addSubview(snap!)
            
            //Third放上面
            let snap2 = toView?.snapshotView(afterScreenUpdates: true)
            transitionContext.containerView.addSubview(snap2!)
            
            snap2?.transform = CGAffineTransform(translationX: -320, y: 0)
            
            UIView.animate(withDuration: transitionTime, delay: aDelay, usingSpringWithDamping: aUsing, initialSpringVelocity: aInitSprVel, options: UIViewAnimationOptions.curveLinear, animations: {
                
                snap2?.transform = CGAffineTransform.identity
            }, completion: { (finished) in
                
                // 删掉截图
                snap?.removeFromSuperview()
                snap2?.removeFromSuperview()
                
                // 添加视图
                transitionContext.containerView.addSubview(toView!)
                
                // 结束 Transition
                let aDidCom = transitionContext.transitionWasCancelled
                transitionContext.completeTransition(!aDidCom)
            })
        }
        else {
            // Third 放下面
            let snap = toView?.snapshotView(afterScreenUpdates: true)
            transitionContext.containerView.addSubview(snap!)
            
            // first 放上面
            let snap2 = fromView?.snapshotView(afterScreenUpdates: true)
            transitionContext.containerView.addSubview(snap2!)
            
            //进行动画
            UIView.animate(withDuration: transitionTime, delay: aDelay, usingSpringWithDamping: aUsing, initialSpringVelocity: aInitSprVel, options: UIViewAnimationOptions.curveLinear, animations: { 
                
                snap2?.transform = CGAffineTransform(translationX: -320, y: 0)
            }, completion: { (finished) in
                
                // 删掉截图
                snap?.removeFromSuperview()
                snap2?.removeFromSuperview()
                
                //添加视图
                transitionContext.containerView.addSubview(fromView!)
                
                //结束Transition
                let aDidCom = transitionContext.transitionWasCancelled
                transitionContext.completeTransition(!aDidCom)
            })
        }
    }
}
  • 在A控制器中 创建一个按钮,用来跳转到B页面:
    override func viewDidLoad() {
        super.viewDidLoad()
     
        let btn = UIButton(type: .contactAdd)
        btn.frame = view.bounds
        btn.setTitle("跳转第二页", for: .normal)
        btn.addTarget(self, action: #selector(clickBtn), for: .touchUpInside)
        self.view.addSubview(btn)
    }

  • 在 跳转的方法中 半透明效果
func clickBtn(){
        let secod = SecondVC()
        
        /// 半透明效果
        self.modalPresentationStyle = .custom
        self.definesPresentationContext = true

        secod.view.backgroundColor = UIColor.init(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 0.5)
        /// 半透明效果
        secod.modalPresentationStyle = .overCurrentContext
        
        /// 转场动画的代理,在 A类中实现
        secod.transitioningDelegate = self
        /// 使用 present 进行跳转
        present(secod, animated: true, completion: nil)
 }
  • 转场动画的代理,在A类中实现
extension ViewController: UIViewControllerTransitioningDelegate {
     // 提供弹出时的动画
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        transition.animationType = AnimationType.present
        return transition
    }
    
    // 提供消失时的动画
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        transition.animationType = AnimationType.dismiss
        return transition
    }
}
  • B控制器中实现的代码只有 一个返回按钮(demo中)
//
//  SecondVC.swift
//  LeftView
//
//  Created by study on 2017/6/30.
//  Copyright © 2017年 WY. All rights reserved.
//

import UIKit

class SecondVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let btn = UIButton(type: .contactAdd)
        btn.frame = CGRect(x: 50, y: 100, width: 200, height: 100)
        btn.setTitle("回到第一页", for: .normal)
        btn.backgroundColor = UIColor.red
        btn.addTarget(self, action: #selector(clickBtn), for: .touchUpInside)
        self.view.addSubview(btn)
    }
    
    func clickBtn(){
        dismiss(animated: true, completion: nil)
    }
}

------------------- 我是懒惰的分界线----------------

下列方法也可以进行跳转,只需要把 present (XXX)方法替换成此方法就好,缺点是,跳转的时候会有黑色的一闪而过

import UIKit

extension UIViewController {
    /// 从左到右
    func presentDetailFromeLeftToRight(_ viewControllerToPresent: UIViewController) {
        let animation = CATransition()
        animation.duration = 0.5
        animation.type = kCATransitionPush
        animation.subtype = kCATransitionFromLeft
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
        
        
        self.view.window?.layer.add(animation, forKey: kCATransition)
        
        present(viewControllerToPresent, animated: false, completion: nil)
    }
    
    /// 从右到左
    func dismissDetailFromeRightToLeft(){
        let animation = CATransition()
        animation.duration = 0.5
        animation.type = kCATransitionPush
        animation.subtype = kCATransitionFromRight
        self.view.window?.layer.add(animation, forKey: kCATransition)
        
        dismiss(animated: false, completion: nil)
    }
}

你可能感兴趣的:(swift 转场动画 从左到右)