原文链接
转场动画
需求:
- 点击导航栏左上角,出现一个左侧菜单
- 左侧菜单覆盖住 原控制器的一半
- 左侧菜单的出现顺序为:从左至右
实现
- 左侧菜单为 UIViewController,
- UIViewController 半透明状态,可以看到 原控制器的数据
- 使用转场动画实现左侧菜单的动画效果
- 使用 modalPresentationStyle 做出 半透明效果
- ViewController 控制器为 第一控制器, 以后简称 A控制器。
- SecondVC 控制器为 第二控制器,以后简称 B控制器
- FadeAnimator 类 是 用来写 转场动画的类。
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)
}
}