最终效果
<br />
1、UI布局
这个界面着实不难....,如果你看了前面的那么多期,这个东西实在是没难度,这里不介绍了……
<br />
<br />
2、实现
其实就是自定义转场动画,这里使用的是自定义拖线的转场动画,其他的就不做介绍了
实现原理
通过设置vc的transitioningDelegate
,然后重写里面的方法,来指定谁来负责present/dismiss动画,在继承UIViewControllerAnimatedTransitioning
来实现动画的过程以及时长
<br />
实现步骤
1、重写override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
方法,获取到UIStoryboardSegue
<br />
2、UIViewControllerTransitioningDelegate
这个代理可以实现动画的监听以及要显示的控制器的大小控制,就是下面的三个方法
-
present
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?
-
dismiss
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
-
一个专门用来处理的要显示的Viewcontroller的类
UIPresentationController
func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController?
<br />
3、在设置动画的执行效果
-
设置动画的时长
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval
-
动画怎么去执行
func animateTransition(transitionContext: UIViewControllerContextTransitioning)
<br />
4、所需要了解的内容
- presented:展示的ViewController(也就是你要显示的那个ViewController)
- presenting:发起的ViewController (也就是你调用present的那个ViewController)
- transitionContext:动画所需要的所有参数(或者说内容)
使用transitionContext
主要就是为了获取要显示的View,和发起的View
一般用toView和fromView表示 - 容器:
transitionContext.containerView()
必须把toView添加到容器中才会显示动画 - 对View进行截屏:
snapshotViewAfterScreenUpdates(true)
使用这个方法
<br /><br /><br />
3、代码实现
OK根据上面的步骤来实现代码:
1、重写prepareForSegue这个方法获取到线,先创建一个类MenuShowAnimator
,并粘贴以下代码
//
// MenuShowAnimator.swift
// ModalAnimator
//
// Created by ios on 16/9/22.
// Copyright © 2016年 ios. All rights reserved.
//
import UIKit
@objc protocol MenuShowAnimatorDelegate : NSObjectProtocol {
func menuShowAnimatorDissmiss()
}
class MenuShowAnimator: NSObject ,UIViewControllerTransitioningDelegate,UIViewControllerAnimatedTransitioning{
var duration : NSTimeInterval = 0.5
var isPresent : Bool = true
private var snapshot :UIView?{
didSet {
if let _delegate = delegate {
let tapGestureRecognizer = UITapGestureRecognizer(target: _delegate, action: #selector(MenuShowAnimatorDelegate.menuShowAnimatorDissmiss))
snapshot?.addGestureRecognizer(tapGestureRecognizer)
}
}
}
weak var delegate:MenuShowAnimatorDelegate?
/**
执行modal的时候会调用 present
- parameter presented: 显示的ViewController
- parameter presenting: 发起的ViewController
- parameter source:
- returns: 谁负责
*/
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?{
isPresent = true
return self
}
/**
执行dismiss的时候会调用 dismiss
- parameter presented: 显示的ViewController
- parameter presenting: 发起的ViewController
- parameter source:
- returns: 谁负责
*/
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?{
isPresent = false
return self
}
}
// MARK: - 动画
extension MenuShowAnimator{
/**
动画时长
- parameter transitionContext: 动画所需要的所有内容
- returns: 时长
*/
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval{
return duration
}
// This method can only be a nop if the transition is interactive and not a percentDriven interactive transition.
/**
负责动画,present dismiss 都要经过这个处理
- parameter transitionContext: 动画所需要的所有内容
*/
func animateTransition(transitionContext: UIViewControllerContextTransitioning){
// 1、发起View
let fromView = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)?.view
// 2、展示View
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)
// 3、容器
let container = transitionContext.containerView()
// 4、设置向下,上的transForm
let moveDown = CGAffineTransformMakeTranslation(0, (container?.bounds.height)! - 150)
let moveUp = CGAffineTransformMakeTranslation(0, -50)
// 5、截屏View
if isPresent {
toView?.transform = moveUp
snapshot = fromView?.snapshotViewAfterScreenUpdates(true)
container?.addSubview(toView!)
container?.addSubview(snapshot!)
}
// 开始动画
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
if self.isPresent{
self.snapshot?.transform = moveDown
toView?.transform = CGAffineTransformIdentity
}else{
self.snapshot?.transform = CGAffineTransformIdentity
fromView?.transform = moveUp
}
}) { (_) in
transitionContext.completeTransition(true)
if !self.isPresent{
self.snapshot?.removeFromSuperview()
}
}
}
}
<br />
2、在ViewController中实现tableView的代理,动画类的代理,重写方法
//
// ViewController.swift
// ModalAnimator
//
// Created by ios on 16/9/22.
// Copyright © 2016年 ios. All rights reserved.
//
import UIKit
class ViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource,MenuShowAnimatorDelegate{
@IBOutlet weak var tableView: UITableView!
private let animationDelegate : MenuShowAnimator = {
let delegate = MenuShowAnimator()
delegate.duration = 0.78
return delegate
}()
override func viewDidLoad() {
super.viewDidLoad()
//设置代理
tableView.delegate = self
tableView.dataSource = self
//不然系统自动布局
automaticallyAdjustsScrollViewInsets = false
//设置标题颜色为 白灰色
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.lightTextColor()]
}
//动画代理
func menuShowAnimatorDissmiss(){
dismissViewControllerAnimated(true, completion: nil)
}
//重写prepareForSegue这个方法获取到线
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//获取下个页面的ViewController
let menuController = segue.destinationViewController as! MenuTableViewController
//用来设置下个页面的选中项
menuController.selectTitle = self.navigationItem.title!
//设置代理
menuController.transitioningDelegate = animationDelegate
//设置模式为自定义
menuController.modalPresentationStyle = .Custom
//设置动画的代理为当前类
animationDelegate.delegate = self
//使用闭包来保存一段代码,当下个页面点击cell的时候调用这个代码
menuController.dismissBlock = {
(title:String) -> Void
in
//设置标题
self.navigationItem.title = title
//执行dismiss动画
self.menuShowAnimatorDissmiss()
}
}
}
// ********************* tableView Delegate *****************
extension ViewController{
//返回多少组
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
//每组多少个
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
//每个的样式
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mainCell", forIndexPath: indexPath) as! MainTableViewCell
cell.backImage.image = UIImage(named: String("animator\(indexPath.row % 4 + 1)"))
return cell
}
}
<br />
3、在显示的出来的MenuViewController中
//
// MenuTableViewController.swift
// ModalAnimator
//
// Created by ios on 16/9/22.
// Copyright © 2016年 ios. All rights reserved.
//
import UIKit
class MenuTableViewController: UITableViewController {
//创建数据源
private lazy var menuItems = ["今日热点","科技","汽车","娱乐","搞笑","生活"]
//默认选择
var selectTitle = "今日热点"
//创建一个闭包
var dismissBlock : ((title : String) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
//返回有多少个cell
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuItems.count
}
//设置每个的样式
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("menuCell", forIndexPath: indexPath) as! MenuTableViewCell
cell.textLabel?.text = menuItems[indexPath.row]
cell.textLabel?.textColor = (menuItems[indexPath.row] == selectTitle) ? UIColor.orangeColor() : UIColor.lightTextColor()
return cell
}
//点击cell的时候触发
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectTitle = menuItems[indexPath.row]
tableView.reloadData()
if let bibao = dismissBlock {
bibao(title:selectTitle)
}
}
}